blob: b1323aef1982ac5509d9dc30db454e9c7e55ca12 [file] [log] [blame]
Simon Glass7581c012017-06-18 22:08:58 -06001#!/usr/bin/python
Tom Rini83d290c2018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glass7581c012017-06-18 22:08:58 -06003#
4# Copyright (C) 2017 Google, Inc
5# Written by Simon Glass <sjg@chromium.org>
6#
Simon Glass7581c012017-06-18 22:08:58 -06007
Simon Glass2be282c2017-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 Glass8fed2eb2017-08-29 14:15:55 -060014import collections
Simon Glass7581c012017-06-18 22:08:58 -060015import copy
Simon Glass2be282c2017-06-18 22:08:59 -060016import sys
Simon Glass7581c012017-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 Glassfbdfd222017-08-29 14:15:48 -060041 fdt.TYPE_INT64: 'fdt64_t',
Simon Glass2be282c2017-06-18 22:08:59 -060042}
Simon Glass7581c012017-06-18 22:08:58 -060043
44STRUCT_PREFIX = 'dtd_'
45VAL_PREFIX = 'dtv_'
46
Simon Glass8fed2eb2017-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 Glass2be282c2017-06-18 22:08:59 -060055def conv_name_to_c(name):
Simon Glass7581c012017-06-18 22:08:58 -060056 """Convert a device-tree name to a C identifier
57
Simon Glass30107b02017-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 Glass7581c012017-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 Glass2be282c2017-06-18 22:08:59 -060066 new = name.replace('@', '_at_')
67 new = new.replace('-', '_')
68 new = new.replace(',', '_')
69 new = new.replace('.', '_')
Simon Glass2be282c2017-06-18 22:08:59 -060070 return new
Simon Glass7581c012017-06-18 22:08:58 -060071
Simon Glass2be282c2017-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 Glass7581c012017-06-18 22:08:58 -060074
Simon Glass2be282c2017-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 Glass56e0bbe2017-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 Glassfbdfd222017-08-29 14:15:48 -0600107 elif ftype == fdt.TYPE_INT64:
108 return '%#x' % value
Simon Glass56e0bbe2017-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 Glass56e0bbe2017-06-18 22:09:02 -0600127
Simon Glass2be282c2017-06-18 22:08:59 -0600128class DtbPlatdata(object):
Simon Glass7581c012017-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 Glass2be282c2017-06-18 22:08:59 -0600136 _fdt: Fdt object, referencing the device tree
Simon Glass7581c012017-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 Glasse36024b2017-06-18 22:09:01 -0600139 _include_disabled: true to include nodes marked status = "disabled"
Simon Glass7581c012017-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 Glass7581c012017-06-18 22:08:58 -0600142 """
Simon Glasse36024b2017-06-18 22:09:01 -0600143 def __init__(self, dtb_fname, include_disabled):
Simon Glass2be282c2017-06-18 22:08:59 -0600144 self._fdt = None
Simon Glass7581c012017-06-18 22:08:58 -0600145 self._dtb_fname = dtb_fname
146 self._valid_nodes = None
Simon Glasse36024b2017-06-18 22:09:01 -0600147 self._include_disabled = include_disabled
Simon Glass7581c012017-06-18 22:08:58 -0600148 self._outfile = None
149 self._lines = []
150 self._aliases = {}
151
Simon Glass2be282c2017-06-18 22:08:59 -0600152 def setup_output(self, fname):
Simon Glass7581c012017-06-18 22:08:58 -0600153 """Set up the output destination
154
Simon Glass2be282c2017-06-18 22:08:59 -0600155 Once this is done, future calls to self.out() will output to this
Simon Glass7581c012017-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 Glass2be282c2017-06-18 22:08:59 -0600166 def out(self, line):
Simon Glass7581c012017-06-18 22:08:58 -0600167 """Output a string to the output file
168
169 Args:
Simon Glass2be282c2017-06-18 22:08:59 -0600170 line: String to output
Simon Glass7581c012017-06-18 22:08:58 -0600171 """
Simon Glass2be282c2017-06-18 22:08:59 -0600172 self._outfile.write(line)
Simon Glass7581c012017-06-18 22:08:58 -0600173
Simon Glass2be282c2017-06-18 22:08:59 -0600174 def buf(self, line):
Simon Glass7581c012017-06-18 22:08:58 -0600175 """Buffer up a string to send later
176
177 Args:
Simon Glass2be282c2017-06-18 22:08:59 -0600178 line: String to add to our 'buffer' list
Simon Glass7581c012017-06-18 22:08:58 -0600179 """
Simon Glass2be282c2017-06-18 22:08:59 -0600180 self._lines.append(line)
Simon Glass7581c012017-06-18 22:08:58 -0600181
Simon Glass2be282c2017-06-18 22:08:59 -0600182 def get_buf(self):
Simon Glass7581c012017-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 Glassd5031142017-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 Glass8fed2eb2017-08-29 14:15:55 -0600202 def get_phandle_argc(self, prop, node_name):
203 """Check if a node contains phandles
Simon Glass2925c262017-08-29 14:15:54 -0600204
Simon Glass8fed2eb2017-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.
Simon Glass2925c262017-08-29 14:15:54 -0600207
Simon Glass8fed2eb2017-08-29 14:15:55 -0600208 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 Glass760b7172018-07-06 10:27:31 -0600214 if not isinstance(prop.value, list):
215 prop.value = [prop.value]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600216 val = prop.value
Simon Glass8fed2eb2017-08-29 14:15:55 -0600217 i = 0
218
219 max_args = 0
220 args = []
221 while i < len(val):
222 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass760b7172018-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 Glass8fed2eb2017-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 Glass2925c262017-08-29 14:15:54 -0600244
Simon Glass2be282c2017-06-18 22:08:59 -0600245 def scan_dtb(self):
Anatolij Gustschinf1a7ba12017-08-18 17:58:51 +0200246 """Scan the device tree to obtain a tree of nodes and properties
Simon Glass7581c012017-06-18 22:08:58 -0600247
Simon Glass2be282c2017-06-18 22:08:59 -0600248 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glass7581c012017-06-18 22:08:58 -0600249 device tree root node, and progress from there.
250 """
Simon Glass2be282c2017-06-18 22:08:59 -0600251 self._fdt = fdt.FdtScan(self._dtb_fname)
Simon Glass7581c012017-06-18 22:08:58 -0600252
Simon Glass2be282c2017-06-18 22:08:59 -0600253 def scan_node(self, root):
254 """Scan a node and subnodes to build a tree of node and phandle info
255
Simon Glass72ab7c52017-08-29 14:15:53 -0600256 This adds each node to self._valid_nodes.
Simon Glass2be282c2017-06-18 22:08:59 -0600257
258 Args:
259 root: Root node for scan
260 """
Simon Glass7581c012017-06-18 22:08:58 -0600261 for node in root.subnodes:
262 if 'compatible' in node.props:
263 status = node.props.get('status')
Simon Glasse36024b2017-06-18 22:09:01 -0600264 if (not self._include_disabled and not status or
Simon Glass2be282c2017-06-18 22:08:59 -0600265 status.value != 'disabled'):
Simon Glass7581c012017-06-18 22:08:58 -0600266 self._valid_nodes.append(node)
Simon Glass7581c012017-06-18 22:08:58 -0600267
268 # recurse to handle any subnodes
Simon Glass2be282c2017-06-18 22:08:59 -0600269 self.scan_node(node)
Simon Glass7581c012017-06-18 22:08:58 -0600270
Simon Glass2be282c2017-06-18 22:08:59 -0600271 def scan_tree(self):
Simon Glass7581c012017-06-18 22:08:58 -0600272 """Scan the device tree for useful information
273
274 This fills in the following properties:
Simon Glass7581c012017-06-18 22:08:58 -0600275 _valid_nodes: A list of nodes we wish to consider include in the
276 platform data
277 """
Simon Glass7581c012017-06-18 22:08:58 -0600278 self._valid_nodes = []
Simon Glass2be282c2017-06-18 22:08:59 -0600279 return self.scan_node(self._fdt.GetRoot())
Simon Glass7581c012017-06-18 22:08:58 -0600280
Simon Glassc20ee0e2017-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:
319 raise ValueError("Node '%s' reg property is not an int")
320 if len(reg.value) % total:
321 raise ValueError("Node '%s' reg property has %d cells "
322 'which is not a multiple of na + ns = %d + %d)' %
323 (node.name, len(reg.value), na, ns))
324 reg.na = na
325 reg.ns = ns
326 if na != 1 or ns != 1:
327 reg.type = fdt.TYPE_INT64
328 i = 0
329 new_value = []
330 val = reg.value
331 if not isinstance(val, list):
332 val = [val]
333 while i < len(val):
334 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
335 i += na
336 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
337 i += ns
338 new_value += [addr, size]
339 reg.value = new_value
340
Simon Glass2be282c2017-06-18 22:08:59 -0600341 def scan_structs(self):
Simon Glass7581c012017-06-18 22:08:58 -0600342 """Scan the device tree building up the C structures we will use.
343
344 Build a dict keyed by C struct name containing a dict of Prop
345 object for each struct field (keyed by property name). Where the
346 same struct appears multiple times, try to use the 'widest'
347 property, i.e. the one with a type which can express all others.
348
349 Once the widest property is determined, all other properties are
350 updated to match that width.
351 """
352 structs = {}
353 for node in self._valid_nodes:
Simon Glass56e0bbe2017-06-18 22:09:02 -0600354 node_name, _ = get_compat_name(node)
Simon Glass7581c012017-06-18 22:08:58 -0600355 fields = {}
356
357 # Get a list of all the valid properties in this node.
358 for name, prop in node.props.items():
359 if name not in PROP_IGNORE_LIST and name[0] != '#':
360 fields[name] = copy.deepcopy(prop)
361
362 # If we've seen this node_name before, update the existing struct.
363 if node_name in structs:
364 struct = structs[node_name]
365 for name, prop in fields.items():
366 oldprop = struct.get(name)
367 if oldprop:
368 oldprop.Widen(prop)
369 else:
370 struct[name] = prop
371
372 # Otherwise store this as a new struct.
373 else:
374 structs[node_name] = fields
375
376 upto = 0
377 for node in self._valid_nodes:
Simon Glass56e0bbe2017-06-18 22:09:02 -0600378 node_name, _ = get_compat_name(node)
Simon Glass7581c012017-06-18 22:08:58 -0600379 struct = structs[node_name]
380 for name, prop in node.props.items():
381 if name not in PROP_IGNORE_LIST and name[0] != '#':
382 prop.Widen(struct[name])
383 upto += 1
384
Simon Glass56e0bbe2017-06-18 22:09:02 -0600385 struct_name, aliases = get_compat_name(node)
Simon Glass7581c012017-06-18 22:08:58 -0600386 for alias in aliases:
387 self._aliases[alias] = struct_name
388
389 return structs
390
Simon Glass2be282c2017-06-18 22:08:59 -0600391 def scan_phandles(self):
Simon Glass7581c012017-06-18 22:08:58 -0600392 """Figure out what phandles each node uses
393
394 We need to be careful when outputing nodes that use phandles since
395 they must come after the declaration of the phandles in the C file.
396 Otherwise we get a compiler error since the phandle struct is not yet
397 declared.
398
399 This function adds to each node a list of phandle nodes that the node
400 depends on. This allows us to output things in the right order.
401 """
402 for node in self._valid_nodes:
403 node.phandles = set()
404 for pname, prop in node.props.items():
405 if pname in PROP_IGNORE_LIST or pname[0] == '#':
406 continue
Simon Glass8fed2eb2017-08-29 14:15:55 -0600407 info = self.get_phandle_argc(prop, node.name)
408 if info:
Simon Glass8fed2eb2017-08-29 14:15:55 -0600409 # Process the list as pairs of (phandle, id)
Simon Glass634eba42017-08-29 14:15:59 -0600410 pos = 0
411 for args in info.args:
412 phandle_cell = prop.value[pos]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600413 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
414 target_node = self._fdt.phandle_to_node[phandle]
415 node.phandles.add(target_node)
Simon Glass634eba42017-08-29 14:15:59 -0600416 pos += 1 + args
Simon Glass7581c012017-06-18 22:08:58 -0600417
418
Simon Glass2be282c2017-06-18 22:08:59 -0600419 def generate_structs(self, structs):
Simon Glass7581c012017-06-18 22:08:58 -0600420 """Generate struct defintions for the platform data
421
422 This writes out the body of a header file consisting of structure
423 definitions for node in self._valid_nodes. See the documentation in
424 README.of-plat for more information.
425 """
Simon Glassd5031142017-08-29 14:16:01 -0600426 self.out_header()
Simon Glass2be282c2017-06-18 22:08:59 -0600427 self.out('#include <stdbool.h>\n')
Masahiro Yamadab08c8c42018-03-05 01:20:11 +0900428 self.out('#include <linux/libfdt.h>\n')
Simon Glass7581c012017-06-18 22:08:58 -0600429
430 # Output the struct definition
431 for name in sorted(structs):
Simon Glass2be282c2017-06-18 22:08:59 -0600432 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glass7581c012017-06-18 22:08:58 -0600433 for pname in sorted(structs[name]):
434 prop = structs[name][pname]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600435 info = self.get_phandle_argc(prop, structs[name])
436 if info:
Simon Glass7581c012017-06-18 22:08:58 -0600437 # For phandles, include a reference to the target
Simon Glass0d154632017-08-29 14:15:56 -0600438 struct_name = 'struct phandle_%d_arg' % info.max_args
439 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass2be282c2017-06-18 22:08:59 -0600440 conv_name_to_c(prop.name),
Simon Glass634eba42017-08-29 14:15:59 -0600441 len(info.args)))
Simon Glass7581c012017-06-18 22:08:58 -0600442 else:
443 ptype = TYPE_NAMES[prop.type]
Simon Glass2be282c2017-06-18 22:08:59 -0600444 self.out('\t%s%s' % (tab_to(2, ptype),
445 conv_name_to_c(prop.name)))
446 if isinstance(prop.value, list):
447 self.out('[%d]' % len(prop.value))
448 self.out(';\n')
449 self.out('};\n')
Simon Glass7581c012017-06-18 22:08:58 -0600450
451 for alias, struct_name in self._aliases.iteritems():
Simon Glass2be282c2017-06-18 22:08:59 -0600452 self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
Simon Glass7581c012017-06-18 22:08:58 -0600453 STRUCT_PREFIX, struct_name))
454
Simon Glass2be282c2017-06-18 22:08:59 -0600455 def output_node(self, node):
Simon Glass7581c012017-06-18 22:08:58 -0600456 """Output the C code for a node
457
458 Args:
459 node: node to output
460 """
Simon Glass56e0bbe2017-06-18 22:09:02 -0600461 struct_name, _ = get_compat_name(node)
Simon Glass2be282c2017-06-18 22:08:59 -0600462 var_name = conv_name_to_c(node.name)
463 self.buf('static struct %s%s %s%s = {\n' %
464 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
Simon Glass7581c012017-06-18 22:08:58 -0600465 for pname, prop in node.props.items():
466 if pname in PROP_IGNORE_LIST or pname[0] == '#':
467 continue
Simon Glass2be282c2017-06-18 22:08:59 -0600468 member_name = conv_name_to_c(prop.name)
469 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
Simon Glass7581c012017-06-18 22:08:58 -0600470
471 # Special handling for lists
Simon Glass2be282c2017-06-18 22:08:59 -0600472 if isinstance(prop.value, list):
473 self.buf('{')
Simon Glass7581c012017-06-18 22:08:58 -0600474 vals = []
475 # For phandles, output a reference to the platform data
476 # of the target node.
Simon Glass8fed2eb2017-08-29 14:15:55 -0600477 info = self.get_phandle_argc(prop, node.name)
478 if info:
Simon Glass7581c012017-06-18 22:08:58 -0600479 # Process the list as pairs of (phandle, id)
Simon Glass634eba42017-08-29 14:15:59 -0600480 pos = 0
481 for args in info.args:
482 phandle_cell = prop.value[pos]
Simon Glass7581c012017-06-18 22:08:58 -0600483 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
Simon Glass72ab7c52017-08-29 14:15:53 -0600484 target_node = self._fdt.phandle_to_node[phandle]
Simon Glass2be282c2017-06-18 22:08:59 -0600485 name = conv_name_to_c(target_node.name)
Simon Glass634eba42017-08-29 14:15:59 -0600486 arg_values = []
487 for i in range(args):
488 arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
489 pos += 1 + args
490 vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
491 ', '.join(arg_values)))
Simon Glass35d50372017-08-29 14:15:57 -0600492 for val in vals:
493 self.buf('\n\t\t%s,' % val)
Simon Glass7581c012017-06-18 22:08:58 -0600494 else:
495 for val in prop.value:
Simon Glass56e0bbe2017-06-18 22:09:02 -0600496 vals.append(get_value(prop.type, val))
Simon Glass21d54ac2017-08-29 14:15:49 -0600497
Simon Glass35d50372017-08-29 14:15:57 -0600498 # Put 8 values per line to avoid very long lines.
499 for i in xrange(0, len(vals), 8):
500 if i:
501 self.buf(',\n\t\t')
502 self.buf(', '.join(vals[i:i + 8]))
Simon Glass2be282c2017-06-18 22:08:59 -0600503 self.buf('}')
Simon Glass7581c012017-06-18 22:08:58 -0600504 else:
Simon Glass56e0bbe2017-06-18 22:09:02 -0600505 self.buf(get_value(prop.type, prop.value))
Simon Glass2be282c2017-06-18 22:08:59 -0600506 self.buf(',\n')
507 self.buf('};\n')
Simon Glass7581c012017-06-18 22:08:58 -0600508
509 # Add a device declaration
Simon Glass2be282c2017-06-18 22:08:59 -0600510 self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
511 self.buf('\t.name\t\t= "%s",\n' % struct_name)
512 self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
513 self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
514 self.buf('};\n')
515 self.buf('\n')
Simon Glass7581c012017-06-18 22:08:58 -0600516
Simon Glass2be282c2017-06-18 22:08:59 -0600517 self.out(''.join(self.get_buf()))
Simon Glass7581c012017-06-18 22:08:58 -0600518
Simon Glass2be282c2017-06-18 22:08:59 -0600519 def generate_tables(self):
Simon Glass7581c012017-06-18 22:08:58 -0600520 """Generate device defintions for the platform data
521
522 This writes out C platform data initialisation data and
523 U_BOOT_DEVICE() declarations for each valid node. Where a node has
524 multiple compatible strings, a #define is used to make them equivalent.
525
526 See the documentation in doc/driver-model/of-plat.txt for more
527 information.
528 """
Simon Glassd5031142017-08-29 14:16:01 -0600529 self.out_header()
Simon Glass2be282c2017-06-18 22:08:59 -0600530 self.out('#include <common.h>\n')
531 self.out('#include <dm.h>\n')
532 self.out('#include <dt-structs.h>\n')
533 self.out('\n')
Simon Glass7581c012017-06-18 22:08:58 -0600534 nodes_to_output = list(self._valid_nodes)
535
536 # Keep outputing nodes until there is none left
537 while nodes_to_output:
538 node = nodes_to_output[0]
539 # Output all the node's dependencies first
540 for req_node in node.phandles:
541 if req_node in nodes_to_output:
Simon Glass2be282c2017-06-18 22:08:59 -0600542 self.output_node(req_node)
Simon Glass7581c012017-06-18 22:08:58 -0600543 nodes_to_output.remove(req_node)
Simon Glass2be282c2017-06-18 22:08:59 -0600544 self.output_node(node)
Simon Glass7581c012017-06-18 22:08:58 -0600545 nodes_to_output.remove(node)
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600546
547
548def run_steps(args, dtb_file, include_disabled, output):
549 """Run all the steps of the dtoc tool
550
551 Args:
552 args: List of non-option arguments provided to the problem
553 dtb_file: Filename of dtb file to process
554 include_disabled: True to include disabled nodes
555 output: Name of output file
556 """
557 if not args:
558 raise ValueError('Please specify a command: struct, platdata')
559
560 plat = DtbPlatdata(dtb_file, include_disabled)
561 plat.scan_dtb()
562 plat.scan_tree()
Simon Glassc20ee0e2017-08-29 14:15:50 -0600563 plat.scan_reg_sizes()
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600564 plat.setup_output(output)
565 structs = plat.scan_structs()
566 plat.scan_phandles()
567
568 for cmd in args[0].split(','):
569 if cmd == 'struct':
570 plat.generate_structs(structs)
571 elif cmd == 'platdata':
572 plat.generate_tables()
573 else:
574 raise ValueError("Unknown command '%s': (use: struct, platdata)" %
575 cmd)