blob: 6cb125944660ca090e224b35b94a4bbf9c4981bf [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
20
21# When we see these properties we ignore them - i.e. do not create a structure member
22PROP_IGNORE_LIST = [
23 '#address-cells',
24 '#gpio-cells',
25 '#size-cells',
26 'compatible',
27 'linux,phandle',
28 "status",
29 'phandle',
30 'u-boot,dm-pre-reloc',
31 'u-boot,dm-tpl',
32 'u-boot,dm-spl',
33]
34
35# C type declarations for the tyues we support
36TYPE_NAMES = {
37 fdt.TYPE_INT: 'fdt32_t',
38 fdt.TYPE_BYTE: 'unsigned char',
39 fdt.TYPE_STRING: 'const char *',
40 fdt.TYPE_BOOL: 'bool',
Simon Glassfc3ae9c2017-08-29 14:15:48 -060041 fdt.TYPE_INT64: 'fdt64_t',
Simon Glass1f730c82017-06-18 22:08:59 -060042}
Simon Glassd570dec2017-06-18 22:08:58 -060043
44STRUCT_PREFIX = 'dtd_'
45VAL_PREFIX = 'dtv_'
46
Simon Glassec3b5e42017-08-29 14:15:55 -060047# This holds information about a property which includes phandles.
48#
49# max_args: integer: Maximum number or arguments that any phandle uses (int).
50# args: Number of args for each phandle in the property. The total number of
51# phandles is len(args). This is a list of integers.
52PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
53
54
Simon Glass1f730c82017-06-18 22:08:59 -060055def conv_name_to_c(name):
Simon Glassd570dec2017-06-18 22:08:58 -060056 """Convert a device-tree name to a C identifier
57
Simon Glass2e0bf3f2017-06-18 22:09:04 -060058 This uses multiple replace() calls instead of re.sub() since it is faster
59 (400ms for 1m calls versus 1000ms for the 're' version).
60
Simon Glassd570dec2017-06-18 22:08:58 -060061 Args:
62 name: Name to convert
63 Return:
64 String containing the C version of this name
65 """
Simon Glass1f730c82017-06-18 22:08:59 -060066 new = name.replace('@', '_at_')
67 new = new.replace('-', '_')
68 new = new.replace(',', '_')
69 new = new.replace('.', '_')
Simon Glass1f730c82017-06-18 22:08:59 -060070 return new
Simon Glassd570dec2017-06-18 22:08:58 -060071
Simon Glass1f730c82017-06-18 22:08:59 -060072def tab_to(num_tabs, line):
73 """Append tabs to a line of text to reach a tab stop.
Simon Glassd570dec2017-06-18 22:08:58 -060074
Simon Glass1f730c82017-06-18 22:08:59 -060075 Args:
76 num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
77 line: Line of text to append to
78
79 Returns:
80 line with the correct number of tabs appeneded. If the line already
81 extends past that tab stop then a single space is appended.
82 """
83 if len(line) >= num_tabs * 8:
84 return line + ' '
85 return line + '\t' * (num_tabs - len(line) // 8)
86
Simon Glass7a2add12017-06-18 22:09:02 -060087def get_value(ftype, value):
88 """Get a value as a C expression
89
90 For integers this returns a byte-swapped (little-endian) hex string
91 For bytes this returns a hex string, e.g. 0x12
92 For strings this returns a literal string enclosed in quotes
93 For booleans this return 'true'
94
95 Args:
96 type: Data type (fdt_util)
97 value: Data value, as a string of bytes
98 """
99 if ftype == fdt.TYPE_INT:
100 return '%#x' % fdt_util.fdt32_to_cpu(value)
101 elif ftype == fdt.TYPE_BYTE:
102 return '%#x' % ord(value[0])
103 elif ftype == fdt.TYPE_STRING:
104 return '"%s"' % value
105 elif ftype == fdt.TYPE_BOOL:
106 return 'true'
Simon Glassfc3ae9c2017-08-29 14:15:48 -0600107 elif ftype == fdt.TYPE_INT64:
108 return '%#x' % value
Simon Glass7a2add12017-06-18 22:09:02 -0600109
110def get_compat_name(node):
111 """Get a node's first compatible string as a C identifier
112
113 Args:
114 node: Node object to check
115 Return:
116 Tuple:
117 C identifier for the first compatible string
118 List of C identifiers for all the other compatible strings
119 (possibly empty)
120 """
121 compat = node.props['compatible'].value
122 aliases = []
123 if isinstance(compat, list):
124 compat, aliases = compat[0], compat[1:]
125 return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases]
126
Simon Glass7a2add12017-06-18 22:09:02 -0600127
Simon Glass1f730c82017-06-18 22:08:59 -0600128class DtbPlatdata(object):
Simon Glassd570dec2017-06-18 22:08:58 -0600129 """Provide a means to convert device tree binary data to platform data
130
131 The output of this process is C structures which can be used in space-
132 constrained encvironments where the ~3KB code overhead of device tree
133 code is not affordable.
134
135 Properties:
Simon Glass1f730c82017-06-18 22:08:59 -0600136 _fdt: Fdt object, referencing the device tree
Simon Glassd570dec2017-06-18 22:08:58 -0600137 _dtb_fname: Filename of the input device tree binary file
138 _valid_nodes: A list of Node object with compatible strings
Simon Glasseab3f622017-06-18 22:09:01 -0600139 _include_disabled: true to include nodes marked status = "disabled"
Simon Glassd570dec2017-06-18 22:08:58 -0600140 _outfile: The current output file (sys.stdout or a real file)
141 _lines: Stashed list of output lines for outputting in the future
Simon Glassd570dec2017-06-18 22:08:58 -0600142 """
Simon Glasseab3f622017-06-18 22:09:01 -0600143 def __init__(self, dtb_fname, include_disabled):
Simon Glass1f730c82017-06-18 22:08:59 -0600144 self._fdt = None
Simon Glassd570dec2017-06-18 22:08:58 -0600145 self._dtb_fname = dtb_fname
146 self._valid_nodes = None
Simon Glasseab3f622017-06-18 22:09:01 -0600147 self._include_disabled = include_disabled
Simon Glassd570dec2017-06-18 22:08:58 -0600148 self._outfile = None
149 self._lines = []
150 self._aliases = {}
151
Simon Glass1f730c82017-06-18 22:08:59 -0600152 def setup_output(self, fname):
Simon Glassd570dec2017-06-18 22:08:58 -0600153 """Set up the output destination
154
Simon Glass1f730c82017-06-18 22:08:59 -0600155 Once this is done, future calls to self.out() will output to this
Simon Glassd570dec2017-06-18 22:08:58 -0600156 file.
157
158 Args:
159 fname: Filename to send output to, or '-' for stdout
160 """
161 if fname == '-':
162 self._outfile = sys.stdout
163 else:
164 self._outfile = open(fname, 'w')
165
Simon Glass1f730c82017-06-18 22:08:59 -0600166 def out(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600167 """Output a string to the output file
168
169 Args:
Simon Glass1f730c82017-06-18 22:08:59 -0600170 line: String to output
Simon Glassd570dec2017-06-18 22:08:58 -0600171 """
Simon Glass1f730c82017-06-18 22:08:59 -0600172 self._outfile.write(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600173
Simon Glass1f730c82017-06-18 22:08:59 -0600174 def buf(self, line):
Simon Glassd570dec2017-06-18 22:08:58 -0600175 """Buffer up a string to send later
176
177 Args:
Simon Glass1f730c82017-06-18 22:08:59 -0600178 line: String to add to our 'buffer' list
Simon Glassd570dec2017-06-18 22:08:58 -0600179 """
Simon Glass1f730c82017-06-18 22:08:59 -0600180 self._lines.append(line)
Simon Glassd570dec2017-06-18 22:08:58 -0600181
Simon Glass1f730c82017-06-18 22:08:59 -0600182 def get_buf(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600183 """Get the contents of the output buffer, and clear it
184
185 Returns:
186 The output buffer, which is then cleared for future use
187 """
188 lines = self._lines
189 self._lines = []
190 return lines
191
Simon Glass68d32c72017-08-29 14:16:01 -0600192 def out_header(self):
193 """Output a message indicating that this is an auto-generated file"""
194 self.out('''/*
195 * DO NOT MODIFY
196 *
197 * This file was generated by dtoc from a .dtb (device tree binary) file.
198 */
199
200''')
201
Simon Glassec3b5e42017-08-29 14:15:55 -0600202 def get_phandle_argc(self, prop, node_name):
203 """Check if a node contains phandles
Simon Glassce5621d2017-08-29 14:15:54 -0600204
Simon Glassec3b5e42017-08-29 14:15:55 -0600205 We have no reliable way of detecting whether a node uses a phandle
206 or not. As an interim measure, use a list of known property names.
207
208 Args:
209 prop: Prop object to check
210 Return:
211 Number of argument cells is this is a phandle, else None
212 """
213 if prop.name in ['clocks']:
Simon Glass609e2b12018-07-06 10:27:31 -0600214 if not isinstance(prop.value, list):
215 prop.value = [prop.value]
Simon Glassec3b5e42017-08-29 14:15:55 -0600216 val = prop.value
Simon Glassec3b5e42017-08-29 14:15:55 -0600217 i = 0
Simon Glassce5621d2017-08-29 14:15:54 -0600218
Simon Glassec3b5e42017-08-29 14:15:55 -0600219 max_args = 0
220 args = []
221 while i < len(val):
222 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass609e2b12018-07-06 10:27:31 -0600223 # If we get to the end of the list, stop. This can happen
224 # since some nodes have more phandles in the list than others,
225 # but we allocate enough space for the largest list. So those
226 # nodes with shorter lists end up with zeroes at the end.
227 if not phandle:
228 break
Simon Glassec3b5e42017-08-29 14:15:55 -0600229 target = self._fdt.phandle_to_node.get(phandle)
230 if not target:
231 raise ValueError("Cannot parse '%s' in node '%s'" %
232 (prop.name, node_name))
233 prop_name = '#clock-cells'
234 cells = target.props.get(prop_name)
235 if not cells:
236 raise ValueError("Node '%s' has no '%s' property" %
237 (target.name, prop_name))
238 num_args = fdt_util.fdt32_to_cpu(cells.value)
239 max_args = max(max_args, num_args)
240 args.append(num_args)
241 i += 1 + num_args
242 return PhandleInfo(max_args, args)
243 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600244
Simon Glass1f730c82017-06-18 22:08:59 -0600245 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200246 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600247
Simon Glass1f730c82017-06-18 22:08:59 -0600248 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600249 device tree root node, and progress from there.
250 """
Simon Glass1f730c82017-06-18 22:08:59 -0600251 self._fdt = fdt.FdtScan(self._dtb_fname)
252
253 def scan_node(self, root):
254 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600255
Simon Glass17ffd622017-08-29 14:15:53 -0600256 This adds each node to self._valid_nodes.
Simon Glass1f730c82017-06-18 22:08:59 -0600257
258 Args:
259 root: Root node for scan
260 """
Simon Glassd570dec2017-06-18 22:08:58 -0600261 for node in root.subnodes:
262 if 'compatible' in node.props:
263 status = node.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600264 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600265 status.value != 'disabled'):
Simon Glassd570dec2017-06-18 22:08:58 -0600266 self._valid_nodes.append(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600267
268 # recurse to handle any subnodes
Simon Glass1f730c82017-06-18 22:08:59 -0600269 self.scan_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600270
Simon Glass1f730c82017-06-18 22:08:59 -0600271 def scan_tree(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600272 """Scan the device tree for useful information
273
274 This fills in the following properties:
Simon Glassd570dec2017-06-18 22:08:58 -0600275 _valid_nodes: A list of nodes we wish to consider include in the
276 platform data
277 """
Simon Glassd570dec2017-06-18 22:08:58 -0600278 self._valid_nodes = []
Simon Glass1f730c82017-06-18 22:08:59 -0600279 return self.scan_node(self._fdt.GetRoot())
Simon Glassd570dec2017-06-18 22:08:58 -0600280
Simon Glass1b1fe412017-08-29 14:15:50 -0600281 @staticmethod
282 def get_num_cells(node):
283 """Get the number of cells in addresses and sizes for this node
284
285 Args:
286 node: Node to check
287
288 Returns:
289 Tuple:
290 Number of address cells for this node
291 Number of size cells for this node
292 """
293 parent = node.parent
294 na, ns = 2, 2
295 if parent:
296 na_prop = parent.props.get('#address-cells')
297 ns_prop = parent.props.get('#size-cells')
298 if na_prop:
299 na = fdt_util.fdt32_to_cpu(na_prop.value)
300 if ns_prop:
301 ns = fdt_util.fdt32_to_cpu(ns_prop.value)
302 return na, ns
303
304 def scan_reg_sizes(self):
305 """Scan for 64-bit 'reg' properties and update the values
306
307 This finds 'reg' properties with 64-bit data and converts the value to
308 an array of 64-values. This allows it to be output in a way that the
309 C code can read.
310 """
311 for node in self._valid_nodes:
312 reg = node.props.get('reg')
313 if not reg:
314 continue
315 na, ns = self.get_num_cells(node)
316 total = na + ns
317
318 if reg.type != fdt.TYPE_INT:
Simon Glassc38fee042018-07-06 10:27:32 -0600319 raise ValueError("Node '%s' reg property is not an int" %
320 node.name)
Simon Glass1b1fe412017-08-29 14:15:50 -0600321 if len(reg.value) % total:
322 raise ValueError("Node '%s' reg property has %d cells "
323 'which is not a multiple of na + ns = %d + %d)' %
324 (node.name, len(reg.value), na, ns))
325 reg.na = na
326 reg.ns = ns
327 if na != 1 or ns != 1:
328 reg.type = fdt.TYPE_INT64
329 i = 0
330 new_value = []
331 val = reg.value
332 if not isinstance(val, list):
333 val = [val]
334 while i < len(val):
335 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
336 i += na
337 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
338 i += ns
339 new_value += [addr, size]
340 reg.value = new_value
341
Simon Glass1f730c82017-06-18 22:08:59 -0600342 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600343 """Scan the device tree building up the C structures we will use.
344
345 Build a dict keyed by C struct name containing a dict of Prop
346 object for each struct field (keyed by property name). Where the
347 same struct appears multiple times, try to use the 'widest'
348 property, i.e. the one with a type which can express all others.
349
350 Once the widest property is determined, all other properties are
351 updated to match that width.
352 """
353 structs = {}
354 for node in self._valid_nodes:
Simon Glass7a2add12017-06-18 22:09:02 -0600355 node_name, _ = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600356 fields = {}
357
358 # Get a list of all the valid properties in this node.
359 for name, prop in node.props.items():
360 if name not in PROP_IGNORE_LIST and name[0] != '#':
361 fields[name] = copy.deepcopy(prop)
362
363 # If we've seen this node_name before, update the existing struct.
364 if node_name in structs:
365 struct = structs[node_name]
366 for name, prop in fields.items():
367 oldprop = struct.get(name)
368 if oldprop:
369 oldprop.Widen(prop)
370 else:
371 struct[name] = prop
372
373 # Otherwise store this as a new struct.
374 else:
375 structs[node_name] = fields
376
377 upto = 0
378 for node in self._valid_nodes:
Simon Glass7a2add12017-06-18 22:09:02 -0600379 node_name, _ = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600380 struct = structs[node_name]
381 for name, prop in node.props.items():
382 if name not in PROP_IGNORE_LIST and name[0] != '#':
383 prop.Widen(struct[name])
384 upto += 1
385
Simon Glass7a2add12017-06-18 22:09:02 -0600386 struct_name, aliases = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600387 for alias in aliases:
388 self._aliases[alias] = struct_name
389
390 return structs
391
Simon Glass1f730c82017-06-18 22:08:59 -0600392 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600393 """Figure out what phandles each node uses
394
395 We need to be careful when outputing nodes that use phandles since
396 they must come after the declaration of the phandles in the C file.
397 Otherwise we get a compiler error since the phandle struct is not yet
398 declared.
399
400 This function adds to each node a list of phandle nodes that the node
401 depends on. This allows us to output things in the right order.
402 """
403 for node in self._valid_nodes:
404 node.phandles = set()
405 for pname, prop in node.props.items():
406 if pname in PROP_IGNORE_LIST or pname[0] == '#':
407 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600408 info = self.get_phandle_argc(prop, node.name)
409 if info:
Simon Glassec3b5e42017-08-29 14:15:55 -0600410 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600411 pos = 0
412 for args in info.args:
413 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600414 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
415 target_node = self._fdt.phandle_to_node[phandle]
416 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600417 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600418
419
Simon Glass1f730c82017-06-18 22:08:59 -0600420 def generate_structs(self, structs):
Simon Glassd570dec2017-06-18 22:08:58 -0600421 """Generate struct defintions for the platform data
422
423 This writes out the body of a header file consisting of structure
424 definitions for node in self._valid_nodes. See the documentation in
425 README.of-plat for more information.
426 """
Simon Glass68d32c72017-08-29 14:16:01 -0600427 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600428 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900429 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600430
431 # Output the struct definition
432 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600433 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600434 for pname in sorted(structs[name]):
435 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600436 info = self.get_phandle_argc(prop, structs[name])
437 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600438 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600439 struct_name = 'struct phandle_%d_arg' % info.max_args
440 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600441 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600442 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600443 else:
444 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600445 self.out('\t%s%s' % (tab_to(2, ptype),
446 conv_name_to_c(prop.name)))
447 if isinstance(prop.value, list):
448 self.out('[%d]' % len(prop.value))
449 self.out(';\n')
450 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600451
452 for alias, struct_name in self._aliases.iteritems():
Simon Glass1f730c82017-06-18 22:08:59 -0600453 self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
Simon Glassd570dec2017-06-18 22:08:58 -0600454 STRUCT_PREFIX, struct_name))
455
Simon Glass1f730c82017-06-18 22:08:59 -0600456 def output_node(self, node):
Simon Glassd570dec2017-06-18 22:08:58 -0600457 """Output the C code for a node
458
459 Args:
460 node: node to output
461 """
Simon Glass7a2add12017-06-18 22:09:02 -0600462 struct_name, _ = get_compat_name(node)
Simon Glass1f730c82017-06-18 22:08:59 -0600463 var_name = conv_name_to_c(node.name)
464 self.buf('static struct %s%s %s%s = {\n' %
465 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
Simon Glassd570dec2017-06-18 22:08:58 -0600466 for pname, prop in node.props.items():
467 if pname in PROP_IGNORE_LIST or pname[0] == '#':
468 continue
Simon Glass1f730c82017-06-18 22:08:59 -0600469 member_name = conv_name_to_c(prop.name)
470 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
Simon Glassd570dec2017-06-18 22:08:58 -0600471
472 # Special handling for lists
Simon Glass1f730c82017-06-18 22:08:59 -0600473 if isinstance(prop.value, list):
474 self.buf('{')
Simon Glassd570dec2017-06-18 22:08:58 -0600475 vals = []
476 # For phandles, output a reference to the platform data
477 # of the target node.
Simon Glassec3b5e42017-08-29 14:15:55 -0600478 info = self.get_phandle_argc(prop, node.name)
479 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600480 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600481 pos = 0
482 for args in info.args:
483 phandle_cell = prop.value[pos]
Simon Glassd570dec2017-06-18 22:08:58 -0600484 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
Simon Glass17ffd622017-08-29 14:15:53 -0600485 target_node = self._fdt.phandle_to_node[phandle]
Simon Glass1f730c82017-06-18 22:08:59 -0600486 name = conv_name_to_c(target_node.name)
Simon Glass3deeb472017-08-29 14:15:59 -0600487 arg_values = []
488 for i in range(args):
489 arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
490 pos += 1 + args
491 vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
492 ', '.join(arg_values)))
Simon Glassd0cd0752017-08-29 14:15:57 -0600493 for val in vals:
494 self.buf('\n\t\t%s,' % val)
Simon Glassd570dec2017-06-18 22:08:58 -0600495 else:
496 for val in prop.value:
Simon Glass7a2add12017-06-18 22:09:02 -0600497 vals.append(get_value(prop.type, val))
Simon Glass131e0b02017-08-29 14:15:49 -0600498
Simon Glassd0cd0752017-08-29 14:15:57 -0600499 # Put 8 values per line to avoid very long lines.
500 for i in xrange(0, len(vals), 8):
501 if i:
502 self.buf(',\n\t\t')
503 self.buf(', '.join(vals[i:i + 8]))
Simon Glass1f730c82017-06-18 22:08:59 -0600504 self.buf('}')
Simon Glassd570dec2017-06-18 22:08:58 -0600505 else:
Simon Glass7a2add12017-06-18 22:09:02 -0600506 self.buf(get_value(prop.type, prop.value))
Simon Glass1f730c82017-06-18 22:08:59 -0600507 self.buf(',\n')
508 self.buf('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600509
510 # Add a device declaration
Simon Glass1f730c82017-06-18 22:08:59 -0600511 self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
512 self.buf('\t.name\t\t= "%s",\n' % struct_name)
513 self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
514 self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
515 self.buf('};\n')
516 self.buf('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600517
Simon Glass1f730c82017-06-18 22:08:59 -0600518 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -0600519
Simon Glass1f730c82017-06-18 22:08:59 -0600520 def generate_tables(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600521 """Generate device defintions for the platform data
522
523 This writes out C platform data initialisation data and
524 U_BOOT_DEVICE() declarations for each valid node. Where a node has
525 multiple compatible strings, a #define is used to make them equivalent.
526
527 See the documentation in doc/driver-model/of-plat.txt for more
528 information.
529 """
Simon Glass68d32c72017-08-29 14:16:01 -0600530 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600531 self.out('#include <common.h>\n')
532 self.out('#include <dm.h>\n')
533 self.out('#include <dt-structs.h>\n')
534 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600535 nodes_to_output = list(self._valid_nodes)
536
537 # Keep outputing nodes until there is none left
538 while nodes_to_output:
539 node = nodes_to_output[0]
540 # Output all the node's dependencies first
541 for req_node in node.phandles:
542 if req_node in nodes_to_output:
Simon Glass1f730c82017-06-18 22:08:59 -0600543 self.output_node(req_node)
Simon Glassd570dec2017-06-18 22:08:58 -0600544 nodes_to_output.remove(req_node)
Simon Glass1f730c82017-06-18 22:08:59 -0600545 self.output_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600546 nodes_to_output.remove(node)
Simon Glass3fa797a2017-06-18 22:09:03 -0600547
548
549def run_steps(args, dtb_file, include_disabled, output):
550 """Run all the steps of the dtoc tool
551
552 Args:
553 args: List of non-option arguments provided to the problem
554 dtb_file: Filename of dtb file to process
555 include_disabled: True to include disabled nodes
556 output: Name of output file
557 """
558 if not args:
559 raise ValueError('Please specify a command: struct, platdata')
560
561 plat = DtbPlatdata(dtb_file, include_disabled)
562 plat.scan_dtb()
563 plat.scan_tree()
Simon Glass1b1fe412017-08-29 14:15:50 -0600564 plat.scan_reg_sizes()
Simon Glass3fa797a2017-06-18 22:09:03 -0600565 plat.setup_output(output)
566 structs = plat.scan_structs()
567 plat.scan_phandles()
568
569 for cmd in args[0].split(','):
570 if cmd == 'struct':
571 plat.generate_structs(structs)
572 elif cmd == 'platdata':
573 plat.generate_tables()
574 else:
575 raise ValueError("Unknown command '%s': (use: struct, platdata)" %
576 cmd)