blob: c5767e5fb41a5d5877036a284fc5a928f8784efb [file] [log] [blame]
Simon Glassd570dec2017-06-18 22:08:58 -06001#!/usr/bin/python
2#
3# Copyright (C) 2017 Google, Inc
4# Written by Simon Glass <sjg@chromium.org>
5#
6# SPDX-License-Identifier: GPL-2.0+
7#
8
Simon Glass1f730c82017-06-18 22:08:59 -06009"""Device tree to platform data class
10
11This supports converting device tree data to C structures definitions and
12static data.
13"""
14
Simon Glassec3b5e42017-08-29 14:15:55 -060015import collections
Simon Glassd570dec2017-06-18 22:08:58 -060016import copy
Simon Glass1f730c82017-06-18 22:08:59 -060017import sys
Simon Glassd570dec2017-06-18 22:08:58 -060018
19import fdt
20import fdt_util
21
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:
103 return '%#x' % ord(value[0])
104 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']:
215 val = prop.value
216 if not isinstance(val, list):
217 val = [val]
218 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])
224 target = self._fdt.phandle_to_node.get(phandle)
225 if not target:
226 raise ValueError("Cannot parse '%s' in node '%s'" %
227 (prop.name, node_name))
228 prop_name = '#clock-cells'
229 cells = target.props.get(prop_name)
230 if not cells:
231 raise ValueError("Node '%s' has no '%s' property" %
232 (target.name, prop_name))
233 num_args = fdt_util.fdt32_to_cpu(cells.value)
234 max_args = max(max_args, num_args)
235 args.append(num_args)
236 i += 1 + num_args
237 return PhandleInfo(max_args, args)
238 return None
Simon Glassce5621d2017-08-29 14:15:54 -0600239
Simon Glass1f730c82017-06-18 22:08:59 -0600240 def scan_dtb(self):
Anatolij Gustschinda707d42017-08-18 17:58:51 +0200241 """Scan the device tree to obtain a tree of nodes and properties
Simon Glassd570dec2017-06-18 22:08:58 -0600242
Simon Glass1f730c82017-06-18 22:08:59 -0600243 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glassd570dec2017-06-18 22:08:58 -0600244 device tree root node, and progress from there.
245 """
Simon Glass1f730c82017-06-18 22:08:59 -0600246 self._fdt = fdt.FdtScan(self._dtb_fname)
247
248 def scan_node(self, root):
249 """Scan a node and subnodes to build a tree of node and phandle info
Simon Glassd570dec2017-06-18 22:08:58 -0600250
Simon Glass17ffd622017-08-29 14:15:53 -0600251 This adds each node to self._valid_nodes.
Simon Glass1f730c82017-06-18 22:08:59 -0600252
253 Args:
254 root: Root node for scan
255 """
Simon Glassd570dec2017-06-18 22:08:58 -0600256 for node in root.subnodes:
257 if 'compatible' in node.props:
258 status = node.props.get('status')
Simon Glasseab3f622017-06-18 22:09:01 -0600259 if (not self._include_disabled and not status or
Simon Glass1f730c82017-06-18 22:08:59 -0600260 status.value != 'disabled'):
Simon Glassd570dec2017-06-18 22:08:58 -0600261 self._valid_nodes.append(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600262
263 # recurse to handle any subnodes
Simon Glass1f730c82017-06-18 22:08:59 -0600264 self.scan_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600265
Simon Glass1f730c82017-06-18 22:08:59 -0600266 def scan_tree(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600267 """Scan the device tree for useful information
268
269 This fills in the following properties:
Simon Glassd570dec2017-06-18 22:08:58 -0600270 _valid_nodes: A list of nodes we wish to consider include in the
271 platform data
272 """
Simon Glassd570dec2017-06-18 22:08:58 -0600273 self._valid_nodes = []
Simon Glass1f730c82017-06-18 22:08:59 -0600274 return self.scan_node(self._fdt.GetRoot())
Simon Glassd570dec2017-06-18 22:08:58 -0600275
Simon Glass1b1fe412017-08-29 14:15:50 -0600276 @staticmethod
277 def get_num_cells(node):
278 """Get the number of cells in addresses and sizes for this node
279
280 Args:
281 node: Node to check
282
283 Returns:
284 Tuple:
285 Number of address cells for this node
286 Number of size cells for this node
287 """
288 parent = node.parent
289 na, ns = 2, 2
290 if parent:
291 na_prop = parent.props.get('#address-cells')
292 ns_prop = parent.props.get('#size-cells')
293 if na_prop:
294 na = fdt_util.fdt32_to_cpu(na_prop.value)
295 if ns_prop:
296 ns = fdt_util.fdt32_to_cpu(ns_prop.value)
297 return na, ns
298
299 def scan_reg_sizes(self):
300 """Scan for 64-bit 'reg' properties and update the values
301
302 This finds 'reg' properties with 64-bit data and converts the value to
303 an array of 64-values. This allows it to be output in a way that the
304 C code can read.
305 """
306 for node in self._valid_nodes:
307 reg = node.props.get('reg')
308 if not reg:
309 continue
310 na, ns = self.get_num_cells(node)
311 total = na + ns
312
313 if reg.type != fdt.TYPE_INT:
314 raise ValueError("Node '%s' reg property is not an int")
315 if len(reg.value) % total:
316 raise ValueError("Node '%s' reg property has %d cells "
317 'which is not a multiple of na + ns = %d + %d)' %
318 (node.name, len(reg.value), na, ns))
319 reg.na = na
320 reg.ns = ns
321 if na != 1 or ns != 1:
322 reg.type = fdt.TYPE_INT64
323 i = 0
324 new_value = []
325 val = reg.value
326 if not isinstance(val, list):
327 val = [val]
328 while i < len(val):
329 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
330 i += na
331 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
332 i += ns
333 new_value += [addr, size]
334 reg.value = new_value
335
Simon Glass1f730c82017-06-18 22:08:59 -0600336 def scan_structs(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600337 """Scan the device tree building up the C structures we will use.
338
339 Build a dict keyed by C struct name containing a dict of Prop
340 object for each struct field (keyed by property name). Where the
341 same struct appears multiple times, try to use the 'widest'
342 property, i.e. the one with a type which can express all others.
343
344 Once the widest property is determined, all other properties are
345 updated to match that width.
346 """
347 structs = {}
348 for node in self._valid_nodes:
Simon Glass7a2add12017-06-18 22:09:02 -0600349 node_name, _ = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600350 fields = {}
351
352 # Get a list of all the valid properties in this node.
353 for name, prop in node.props.items():
354 if name not in PROP_IGNORE_LIST and name[0] != '#':
355 fields[name] = copy.deepcopy(prop)
356
357 # If we've seen this node_name before, update the existing struct.
358 if node_name in structs:
359 struct = structs[node_name]
360 for name, prop in fields.items():
361 oldprop = struct.get(name)
362 if oldprop:
363 oldprop.Widen(prop)
364 else:
365 struct[name] = prop
366
367 # Otherwise store this as a new struct.
368 else:
369 structs[node_name] = fields
370
371 upto = 0
372 for node in self._valid_nodes:
Simon Glass7a2add12017-06-18 22:09:02 -0600373 node_name, _ = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600374 struct = structs[node_name]
375 for name, prop in node.props.items():
376 if name not in PROP_IGNORE_LIST and name[0] != '#':
377 prop.Widen(struct[name])
378 upto += 1
379
Simon Glass7a2add12017-06-18 22:09:02 -0600380 struct_name, aliases = get_compat_name(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600381 for alias in aliases:
382 self._aliases[alias] = struct_name
383
384 return structs
385
Simon Glass1f730c82017-06-18 22:08:59 -0600386 def scan_phandles(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600387 """Figure out what phandles each node uses
388
389 We need to be careful when outputing nodes that use phandles since
390 they must come after the declaration of the phandles in the C file.
391 Otherwise we get a compiler error since the phandle struct is not yet
392 declared.
393
394 This function adds to each node a list of phandle nodes that the node
395 depends on. This allows us to output things in the right order.
396 """
397 for node in self._valid_nodes:
398 node.phandles = set()
399 for pname, prop in node.props.items():
400 if pname in PROP_IGNORE_LIST or pname[0] == '#':
401 continue
Simon Glassec3b5e42017-08-29 14:15:55 -0600402 info = self.get_phandle_argc(prop, node.name)
403 if info:
404 if not isinstance(prop.value, list):
405 prop.value = [prop.value]
406 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600407 pos = 0
408 for args in info.args:
409 phandle_cell = prop.value[pos]
Simon Glassec3b5e42017-08-29 14:15:55 -0600410 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
411 target_node = self._fdt.phandle_to_node[phandle]
412 node.phandles.add(target_node)
Simon Glass3deeb472017-08-29 14:15:59 -0600413 pos += 1 + args
Simon Glassd570dec2017-06-18 22:08:58 -0600414
415
Simon Glass1f730c82017-06-18 22:08:59 -0600416 def generate_structs(self, structs):
Simon Glassd570dec2017-06-18 22:08:58 -0600417 """Generate struct defintions for the platform data
418
419 This writes out the body of a header file consisting of structure
420 definitions for node in self._valid_nodes. See the documentation in
421 README.of-plat for more information.
422 """
Simon Glass68d32c72017-08-29 14:16:01 -0600423 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600424 self.out('#include <stdbool.h>\n')
Masahiro Yamada75f82d02018-03-05 01:20:11 +0900425 self.out('#include <linux/libfdt.h>\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600426
427 # Output the struct definition
428 for name in sorted(structs):
Simon Glass1f730c82017-06-18 22:08:59 -0600429 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glassd570dec2017-06-18 22:08:58 -0600430 for pname in sorted(structs[name]):
431 prop = structs[name][pname]
Simon Glassec3b5e42017-08-29 14:15:55 -0600432 info = self.get_phandle_argc(prop, structs[name])
433 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600434 # For phandles, include a reference to the target
Simon Glasse94414b2017-08-29 14:15:56 -0600435 struct_name = 'struct phandle_%d_arg' % info.max_args
436 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass1f730c82017-06-18 22:08:59 -0600437 conv_name_to_c(prop.name),
Simon Glass3deeb472017-08-29 14:15:59 -0600438 len(info.args)))
Simon Glassd570dec2017-06-18 22:08:58 -0600439 else:
440 ptype = TYPE_NAMES[prop.type]
Simon Glass1f730c82017-06-18 22:08:59 -0600441 self.out('\t%s%s' % (tab_to(2, ptype),
442 conv_name_to_c(prop.name)))
443 if isinstance(prop.value, list):
444 self.out('[%d]' % len(prop.value))
445 self.out(';\n')
446 self.out('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600447
448 for alias, struct_name in self._aliases.iteritems():
Simon Glass1f730c82017-06-18 22:08:59 -0600449 self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
Simon Glassd570dec2017-06-18 22:08:58 -0600450 STRUCT_PREFIX, struct_name))
451
Simon Glass1f730c82017-06-18 22:08:59 -0600452 def output_node(self, node):
Simon Glassd570dec2017-06-18 22:08:58 -0600453 """Output the C code for a node
454
455 Args:
456 node: node to output
457 """
Simon Glass7a2add12017-06-18 22:09:02 -0600458 struct_name, _ = get_compat_name(node)
Simon Glass1f730c82017-06-18 22:08:59 -0600459 var_name = conv_name_to_c(node.name)
460 self.buf('static struct %s%s %s%s = {\n' %
461 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
Simon Glassd570dec2017-06-18 22:08:58 -0600462 for pname, prop in node.props.items():
463 if pname in PROP_IGNORE_LIST or pname[0] == '#':
464 continue
Simon Glass1f730c82017-06-18 22:08:59 -0600465 member_name = conv_name_to_c(prop.name)
466 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
Simon Glassd570dec2017-06-18 22:08:58 -0600467
468 # Special handling for lists
Simon Glass1f730c82017-06-18 22:08:59 -0600469 if isinstance(prop.value, list):
470 self.buf('{')
Simon Glassd570dec2017-06-18 22:08:58 -0600471 vals = []
472 # For phandles, output a reference to the platform data
473 # of the target node.
Simon Glassec3b5e42017-08-29 14:15:55 -0600474 info = self.get_phandle_argc(prop, node.name)
475 if info:
Simon Glassd570dec2017-06-18 22:08:58 -0600476 # Process the list as pairs of (phandle, id)
Simon Glass3deeb472017-08-29 14:15:59 -0600477 pos = 0
478 for args in info.args:
479 phandle_cell = prop.value[pos]
Simon Glassd570dec2017-06-18 22:08:58 -0600480 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
Simon Glass17ffd622017-08-29 14:15:53 -0600481 target_node = self._fdt.phandle_to_node[phandle]
Simon Glass1f730c82017-06-18 22:08:59 -0600482 name = conv_name_to_c(target_node.name)
Simon Glass3deeb472017-08-29 14:15:59 -0600483 arg_values = []
484 for i in range(args):
485 arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
486 pos += 1 + args
487 vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
488 ', '.join(arg_values)))
Simon Glassd0cd0752017-08-29 14:15:57 -0600489 for val in vals:
490 self.buf('\n\t\t%s,' % val)
Simon Glassd570dec2017-06-18 22:08:58 -0600491 else:
492 for val in prop.value:
Simon Glass7a2add12017-06-18 22:09:02 -0600493 vals.append(get_value(prop.type, val))
Simon Glass131e0b02017-08-29 14:15:49 -0600494
Simon Glassd0cd0752017-08-29 14:15:57 -0600495 # Put 8 values per line to avoid very long lines.
496 for i in xrange(0, len(vals), 8):
497 if i:
498 self.buf(',\n\t\t')
499 self.buf(', '.join(vals[i:i + 8]))
Simon Glass1f730c82017-06-18 22:08:59 -0600500 self.buf('}')
Simon Glassd570dec2017-06-18 22:08:58 -0600501 else:
Simon Glass7a2add12017-06-18 22:09:02 -0600502 self.buf(get_value(prop.type, prop.value))
Simon Glass1f730c82017-06-18 22:08:59 -0600503 self.buf(',\n')
504 self.buf('};\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600505
506 # Add a device declaration
Simon Glass1f730c82017-06-18 22:08:59 -0600507 self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
508 self.buf('\t.name\t\t= "%s",\n' % struct_name)
509 self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
510 self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
511 self.buf('};\n')
512 self.buf('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600513
Simon Glass1f730c82017-06-18 22:08:59 -0600514 self.out(''.join(self.get_buf()))
Simon Glassd570dec2017-06-18 22:08:58 -0600515
Simon Glass1f730c82017-06-18 22:08:59 -0600516 def generate_tables(self):
Simon Glassd570dec2017-06-18 22:08:58 -0600517 """Generate device defintions for the platform data
518
519 This writes out C platform data initialisation data and
520 U_BOOT_DEVICE() declarations for each valid node. Where a node has
521 multiple compatible strings, a #define is used to make them equivalent.
522
523 See the documentation in doc/driver-model/of-plat.txt for more
524 information.
525 """
Simon Glass68d32c72017-08-29 14:16:01 -0600526 self.out_header()
Simon Glass1f730c82017-06-18 22:08:59 -0600527 self.out('#include <common.h>\n')
528 self.out('#include <dm.h>\n')
529 self.out('#include <dt-structs.h>\n')
530 self.out('\n')
Simon Glassd570dec2017-06-18 22:08:58 -0600531 nodes_to_output = list(self._valid_nodes)
532
533 # Keep outputing nodes until there is none left
534 while nodes_to_output:
535 node = nodes_to_output[0]
536 # Output all the node's dependencies first
537 for req_node in node.phandles:
538 if req_node in nodes_to_output:
Simon Glass1f730c82017-06-18 22:08:59 -0600539 self.output_node(req_node)
Simon Glassd570dec2017-06-18 22:08:58 -0600540 nodes_to_output.remove(req_node)
Simon Glass1f730c82017-06-18 22:08:59 -0600541 self.output_node(node)
Simon Glassd570dec2017-06-18 22:08:58 -0600542 nodes_to_output.remove(node)
Simon Glass3fa797a2017-06-18 22:09:03 -0600543
544
545def run_steps(args, dtb_file, include_disabled, output):
546 """Run all the steps of the dtoc tool
547
548 Args:
549 args: List of non-option arguments provided to the problem
550 dtb_file: Filename of dtb file to process
551 include_disabled: True to include disabled nodes
552 output: Name of output file
553 """
554 if not args:
555 raise ValueError('Please specify a command: struct, platdata')
556
557 plat = DtbPlatdata(dtb_file, include_disabled)
558 plat.scan_dtb()
559 plat.scan_tree()
Simon Glass1b1fe412017-08-29 14:15:50 -0600560 plat.scan_reg_sizes()
Simon Glass3fa797a2017-06-18 22:09:03 -0600561 plat.setup_output(output)
562 structs = plat.scan_structs()
563 plat.scan_phandles()
564
565 for cmd in args[0].split(','):
566 if cmd == 'struct':
567 plat.generate_structs(structs)
568 elif cmd == 'platdata':
569 plat.generate_tables()
570 else:
571 raise ValueError("Unknown command '%s': (use: struct, platdata)" %
572 cmd)