blob: 2f7302e52958ed46c217fc7c10499f90aa353a0a [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']:
214 val = prop.value
215 if not isinstance(val, list):
216 val = [val]
217 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])
223 target = self._fdt.phandle_to_node.get(phandle)
224 if not target:
225 raise ValueError("Cannot parse '%s' in node '%s'" %
226 (prop.name, node_name))
227 prop_name = '#clock-cells'
228 cells = target.props.get(prop_name)
229 if not cells:
230 raise ValueError("Node '%s' has no '%s' property" %
231 (target.name, prop_name))
232 num_args = fdt_util.fdt32_to_cpu(cells.value)
233 max_args = max(max_args, num_args)
234 args.append(num_args)
235 i += 1 + num_args
236 return PhandleInfo(max_args, args)
237 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600238
Simon Glass1f730c82017-06-18 22:08:59 -0600239 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200240 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600241
Simon Glass1f730c82017-06-18 22:08:59 -0600242 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600243 device tree root node, and progress from there.
244 """
Simon Glass1f730c82017-06-18 22:08:59 -0600245 self._fdt = fdt.FdtScan(self._dtb_fname)
246
247 def scan_node(self, root):
248 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600249
Simon Glass17ffd622017-08-29 14:15:53 -0600250 This adds each node to self._valid_nodes.
Simon Glass1f730c82017-06-18 22:08:59 -0600251
252 Args:
253 root: Root node for scan
254 """
Simon Glassd570dec2017-06-18 22:08:58 -0600255 for node in root.subnodes:
256 if 'compatible' in node.props:
257 status = node.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600258 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600259 status.value != 'disabled'):
Simon Glassd570dec2017-06-18 22:08:58 -0600260 self._valid_nodes.append(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600261
262 # recurse to handle any subnodes
Simon Glass1f730c82017-06-18 22:08:59 -0600263 self.scan_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600264
Simon Glass1f730c82017-06-18 22:08:59 -0600265 def scan_tree(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600266 """Scan the device tree for useful information
267
268 This fills in the following properties:
Simon Glassd570dec2017-06-18 22:08:58 -0600269 _valid_nodes: A list of nodes we wish to consider include in the
270 platform data
271 """
Simon Glassd570dec2017-06-18 22:08:58 -0600272 self._valid_nodes = []
Simon Glass1f730c82017-06-18 22:08:59 -0600273 return self.scan_node(self._fdt.GetRoot())
Simon Glassd570dec2017-06-18 22:08:58 -0600274
Simon Glass1b1fe412017-08-29 14:15:50 -0600275 @staticmethod
276 def get_num_cells(node):
277 """Get the number of cells in addresses and sizes for this node
278
279 Args:
280 node: Node to check
281
282 Returns:
283 Tuple:
284 Number of address cells for this node
285 Number of size cells for this node
286 """
287 parent = node.parent
288 na, ns = 2, 2
289 if parent:
290 na_prop = parent.props.get('#address-cells')
291 ns_prop = parent.props.get('#size-cells')
292 if na_prop:
293 na = fdt_util.fdt32_to_cpu(na_prop.value)
294 if ns_prop:
295 ns = fdt_util.fdt32_to_cpu(ns_prop.value)
296 return na, ns
297
298 def scan_reg_sizes(self):
299 """Scan for 64-bit 'reg' properties and update the values
300
301 This finds 'reg' properties with 64-bit data and converts the value to
302 an array of 64-values. This allows it to be output in a way that the
303 C code can read.
304 """
305 for node in self._valid_nodes:
306 reg = node.props.get('reg')
307 if not reg:
308 continue
309 na, ns = self.get_num_cells(node)
310 total = na + ns
311
312 if reg.type != fdt.TYPE_INT:
313 raise ValueError("Node '%s' reg property is not an int")
314 if len(reg.value) % total:
315 raise ValueError("Node '%s' reg property has %d cells "
316 'which is not a multiple of na + ns = %d + %d)' %
317 (node.name, len(reg.value), na, ns))
318 reg.na = na
319 reg.ns = ns
320 if na != 1 or ns != 1:
321 reg.type = fdt.TYPE_INT64
322 i = 0
323 new_value = []
324 val = reg.value
325 if not isinstance(val, list):
326 val = [val]
327 while i < len(val):
328 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
329 i += na
330 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
331 i += ns
332 new_value += [addr, size]
333 reg.value = new_value
334
Simon Glass1f730c82017-06-18 22:08:59 -0600335 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600336 """Scan the device tree building up the C structures we will use.
337
338 Build a dict keyed by C struct name containing a dict of Prop
339 object for each struct field (keyed by property name). Where the
340 same struct appears multiple times, try to use the 'widest'
341 property, i.e. the one with a type which can express all others.
342
343 Once the widest property is determined, all other properties are
344 updated to match that width.
345 """
346 structs = {}
347 for node in self._valid_nodes:
Simon Glass7a2add12017-06-18 22:09:02 -0600348 node_name, _ = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600349 fields = {}
350
351 # Get a list of all the valid properties in this node.
352 for name, prop in node.props.items():
353 if name not in PROP_IGNORE_LIST and name[0] != '#':
354 fields[name] = copy.deepcopy(prop)
355
356 # If we've seen this node_name before, update the existing struct.
357 if node_name in structs:
358 struct = structs[node_name]
359 for name, prop in fields.items():
360 oldprop = struct.get(name)
361 if oldprop:
362 oldprop.Widen(prop)
363 else:
364 struct[name] = prop
365
366 # Otherwise store this as a new struct.
367 else:
368 structs[node_name] = fields
369
370 upto = 0
371 for node in self._valid_nodes:
Simon Glass7a2add12017-06-18 22:09:02 -0600372 node_name, _ = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600373 struct = structs[node_name]
374 for name, prop in node.props.items():
375 if name not in PROP_IGNORE_LIST and name[0] != '#':
376 prop.Widen(struct[name])
377 upto += 1
378
Simon Glass7a2add12017-06-18 22:09:02 -0600379 struct_name, aliases = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600380 for alias in aliases:
381 self._aliases[alias] = struct_name
382
383 return structs
384
Simon Glass1f730c82017-06-18 22:08:59 -0600385 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600386 """Figure out what phandles each node uses
387
388 We need to be careful when outputing nodes that use phandles since
389 they must come after the declaration of the phandles in the C file.
390 Otherwise we get a compiler error since the phandle struct is not yet
391 declared.
392
393 This function adds to each node a list of phandle nodes that the node
394 depends on. This allows us to output things in the right order.
395 """
396 for node in self._valid_nodes:
397 node.phandles = set()
398 for pname, prop in node.props.items():
399 if pname in PROP_IGNORE_LIST or pname[0] == '#':
400 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600401 info = self.get_phandle_argc(prop, node.name)
402 if info:
403 if not isinstance(prop.value, list):
404 prop.value = [prop.value]
405 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600406 pos = 0
407 for args in info.args:
408 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600409 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
410 target_node = self._fdt.phandle_to_node[phandle]
411 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600412 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600413
414
Simon Glass1f730c82017-06-18 22:08:59 -0600415 def generate_structs(self, structs):
Simon Glassd570dec2017-06-18 22:08:58 -0600416 """Generate struct defintions for the platform data
417
418 This writes out the body of a header file consisting of structure
419 definitions for node in self._valid_nodes. See the documentation in
420 README.of-plat for more information.
421 """
Simon Glass68d32c72017-08-29 14:16:01 -0600422 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600423 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900424 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600425
426 # Output the struct definition
427 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600428 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600429 for pname in sorted(structs[name]):
430 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600431 info = self.get_phandle_argc(prop, structs[name])
432 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600433 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600434 struct_name = 'struct phandle_%d_arg' % info.max_args
435 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600436 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600437 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600438 else:
439 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600440 self.out('\t%s%s' % (tab_to(2, ptype),
441 conv_name_to_c(prop.name)))
442 if isinstance(prop.value, list):
443 self.out('[%d]' % len(prop.value))
444 self.out(';\n')
445 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600446
447 for alias, struct_name in self._aliases.iteritems():
Simon Glass1f730c82017-06-18 22:08:59 -0600448 self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
Simon Glassd570dec2017-06-18 22:08:58 -0600449 STRUCT_PREFIX, struct_name))
450
Simon Glass1f730c82017-06-18 22:08:59 -0600451 def output_node(self, node):
Simon Glassd570dec2017-06-18 22:08:58 -0600452 """Output the C code for a node
453
454 Args:
455 node: node to output
456 """
Simon Glass7a2add12017-06-18 22:09:02 -0600457 struct_name, _ = get_compat_name(node)
Simon Glass1f730c82017-06-18 22:08:59 -0600458 var_name = conv_name_to_c(node.name)
459 self.buf('static struct %s%s %s%s = {\n' %
460 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
Simon Glassd570dec2017-06-18 22:08:58 -0600461 for pname, prop in node.props.items():
462 if pname in PROP_IGNORE_LIST or pname[0] == '#':
463 continue
Simon Glass1f730c82017-06-18 22:08:59 -0600464 member_name = conv_name_to_c(prop.name)
465 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
Simon Glassd570dec2017-06-18 22:08:58 -0600466
467 # Special handling for lists
Simon Glass1f730c82017-06-18 22:08:59 -0600468 if isinstance(prop.value, list):
469 self.buf('{')
Simon Glassd570dec2017-06-18 22:08:58 -0600470 vals = []
471 # For phandles, output a reference to the platform data
472 # of the target node.
Simon Glassec3b5e42017-08-29 14:15:55 -0600473 info = self.get_phandle_argc(prop, node.name)
474 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600475 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600476 pos = 0
477 for args in info.args:
478 phandle_cell = prop.value[pos]
Simon Glassd570dec2017-06-18 22:08:58 -0600479 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
Simon Glass17ffd622017-08-29 14:15:53 -0600480 target_node = self._fdt.phandle_to_node[phandle]
Simon Glass1f730c82017-06-18 22:08:59 -0600481 name = conv_name_to_c(target_node.name)
Simon Glass3deeb472017-08-29 14:15:59 -0600482 arg_values = []
483 for i in range(args):
484 arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
485 pos += 1 + args
486 vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
487 ', '.join(arg_values)))
Simon Glassd0cd0752017-08-29 14:15:57 -0600488 for val in vals:
489 self.buf('\n\t\t%s,' % val)
Simon Glassd570dec2017-06-18 22:08:58 -0600490 else:
491 for val in prop.value:
Simon Glass7a2add12017-06-18 22:09:02 -0600492 vals.append(get_value(prop.type, val))
Simon Glass131e0b02017-08-29 14:15:49 -0600493
Simon Glassd0cd0752017-08-29 14:15:57 -0600494 # Put 8 values per line to avoid very long lines.
495 for i in xrange(0, len(vals), 8):
496 if i:
497 self.buf(',\n\t\t')
498 self.buf(', '.join(vals[i:i + 8]))
Simon Glass1f730c82017-06-18 22:08:59 -0600499 self.buf('}')
Simon Glassd570dec2017-06-18 22:08:58 -0600500 else:
Simon Glass7a2add12017-06-18 22:09:02 -0600501 self.buf(get_value(prop.type, prop.value))
Simon Glass1f730c82017-06-18 22:08:59 -0600502 self.buf(',\n')
503 self.buf('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600504
505 # Add a device declaration
Simon Glass1f730c82017-06-18 22:08:59 -0600506 self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
507 self.buf('\t.name\t\t= "%s",\n' % struct_name)
508 self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
509 self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
510 self.buf('};\n')
511 self.buf('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600512
Simon Glass1f730c82017-06-18 22:08:59 -0600513 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -0600514
Simon Glass1f730c82017-06-18 22:08:59 -0600515 def generate_tables(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600516 """Generate device defintions for the platform data
517
518 This writes out C platform data initialisation data and
519 U_BOOT_DEVICE() declarations for each valid node. Where a node has
520 multiple compatible strings, a #define is used to make them equivalent.
521
522 See the documentation in doc/driver-model/of-plat.txt for more
523 information.
524 """
Simon Glass68d32c72017-08-29 14:16:01 -0600525 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600526 self.out('#include <common.h>\n')
527 self.out('#include <dm.h>\n')
528 self.out('#include <dt-structs.h>\n')
529 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600530 nodes_to_output = list(self._valid_nodes)
531
532 # Keep outputing nodes until there is none left
533 while nodes_to_output:
534 node = nodes_to_output[0]
535 # Output all the node's dependencies first
536 for req_node in node.phandles:
537 if req_node in nodes_to_output:
Simon Glass1f730c82017-06-18 22:08:59 -0600538 self.output_node(req_node)
Simon Glassd570dec2017-06-18 22:08:58 -0600539 nodes_to_output.remove(req_node)
Simon Glass1f730c82017-06-18 22:08:59 -0600540 self.output_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600541 nodes_to_output.remove(node)
Simon Glass3fa797a2017-06-18 22:09:03 -0600542
543
544def run_steps(args, dtb_file, include_disabled, output):
545 """Run all the steps of the dtoc tool
546
547 Args:
548 args: List of non-option arguments provided to the problem
549 dtb_file: Filename of dtb file to process
550 include_disabled: True to include disabled nodes
551 output: Name of output file
552 """
553 if not args:
554 raise ValueError('Please specify a command: struct, platdata')
555
556 plat = DtbPlatdata(dtb_file, include_disabled)
557 plat.scan_dtb()
558 plat.scan_tree()
Simon Glass1b1fe412017-08-29 14:15:50 -0600559 plat.scan_reg_sizes()
Simon Glass3fa797a2017-06-18 22:09:03 -0600560 plat.setup_output(output)
561 structs = plat.scan_structs()
562 plat.scan_phandles()
563
564 for cmd in args[0].split(','):
565 if cmd == 'struct':
566 plat.generate_structs(structs)
567 elif cmd == 'platdata':
568 plat.generate_tables()
569 else:
570 raise ValueError("Unknown command '%s': (use: struct, platdata)" %
571 cmd)