blob: bc0de426a9ac968b237cf5409388f17efee16fe9 [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
Simon Glassbf776672020-04-17 18:09:04 -060018from dtoc import fdt
19from dtoc import fdt_util
20from patman import tools
Simon Glass7581c012017-06-18 22:08:58 -060021
22# When we see these properties we ignore them - i.e. do not create a structure member
23PROP_IGNORE_LIST = [
24 '#address-cells',
25 '#gpio-cells',
26 '#size-cells',
27 'compatible',
28 'linux,phandle',
29 "status",
30 'phandle',
31 'u-boot,dm-pre-reloc',
32 'u-boot,dm-tpl',
33 'u-boot,dm-spl',
34]
35
36# C type declarations for the tyues we support
37TYPE_NAMES = {
38 fdt.TYPE_INT: 'fdt32_t',
39 fdt.TYPE_BYTE: 'unsigned char',
40 fdt.TYPE_STRING: 'const char *',
41 fdt.TYPE_BOOL: 'bool',
Simon Glassfbdfd222017-08-29 14:15:48 -060042 fdt.TYPE_INT64: 'fdt64_t',
Simon Glass2be282c2017-06-18 22:08:59 -060043}
Simon Glass7581c012017-06-18 22:08:58 -060044
45STRUCT_PREFIX = 'dtd_'
46VAL_PREFIX = 'dtv_'
47
Simon Glass8fed2eb2017-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 Glass2be282c2017-06-18 22:08:59 -060056def conv_name_to_c(name):
Simon Glass7581c012017-06-18 22:08:58 -060057 """Convert a device-tree name to a C identifier
58
Simon Glass30107b02017-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 Glass7581c012017-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 Glass2be282c2017-06-18 22:08:59 -060067 new = name.replace('@', '_at_')
68 new = new.replace('-', '_')
69 new = new.replace(',', '_')
70 new = new.replace('.', '_')
Simon Glass2be282c2017-06-18 22:08:59 -060071 return new
Simon Glass7581c012017-06-18 22:08:58 -060072
Simon Glass2be282c2017-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 Glass7581c012017-06-18 22:08:58 -060075
Simon Glass2be282c2017-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 Glass56e0bbe2017-06-18 22:09:02 -060088def get_value(ftype, value):
89 """Get a value as a C expression
90
91 For integers this returns a byte-swapped (little-endian) hex string
92 For bytes this returns a hex string, e.g. 0x12
93 For strings this returns a literal string enclosed in quotes
94 For booleans this return 'true'
95
96 Args:
97 type: Data type (fdt_util)
98 value: Data value, as a string of bytes
99 """
100 if ftype == fdt.TYPE_INT:
101 return '%#x' % fdt_util.fdt32_to_cpu(value)
102 elif ftype == fdt.TYPE_BYTE:
Simon Glass9b044f72019-05-17 22:00:43 -0600103 return '%#x' % tools.ToByte(value[0])
Simon Glass56e0bbe2017-06-18 22:09:02 -0600104 elif ftype == fdt.TYPE_STRING:
105 return '"%s"' % value
106 elif ftype == fdt.TYPE_BOOL:
107 return 'true'
Simon Glassfbdfd222017-08-29 14:15:48 -0600108 elif ftype == fdt.TYPE_INT64:
109 return '%#x' % value
Simon Glass56e0bbe2017-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 Glass56e0bbe2017-06-18 22:09:02 -0600128
Simon Glass2be282c2017-06-18 22:08:59 -0600129class DtbPlatdata(object):
Simon Glass7581c012017-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 Glass2be282c2017-06-18 22:08:59 -0600137 _fdt: Fdt object, referencing the device tree
Simon Glass7581c012017-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 Glasse36024b2017-06-18 22:09:01 -0600140 _include_disabled: true to include nodes marked status = "disabled"
Simon Glass7581c012017-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
Walter Lozanoace16e82020-06-25 01:10:05 -0300143 _aliases: Dict that hold aliases for compatible strings
144 key: First compatible string declared in a node
145 value: List of additional compatible strings declared in a node
Simon Glass7581c012017-06-18 22:08:58 -0600146 """
Simon Glasse36024b2017-06-18 22:09:01 -0600147 def __init__(self, dtb_fname, include_disabled):
Simon Glass2be282c2017-06-18 22:08:59 -0600148 self._fdt = None
Simon Glass7581c012017-06-18 22:08:58 -0600149 self._dtb_fname = dtb_fname
150 self._valid_nodes = None
Simon Glasse36024b2017-06-18 22:09:01 -0600151 self._include_disabled = include_disabled
Simon Glass7581c012017-06-18 22:08:58 -0600152 self._outfile = None
153 self._lines = []
154 self._aliases = {}
155
Simon Glass2be282c2017-06-18 22:08:59 -0600156 def setup_output(self, fname):
Simon Glass7581c012017-06-18 22:08:58 -0600157 """Set up the output destination
158
Simon Glass2be282c2017-06-18 22:08:59 -0600159 Once this is done, future calls to self.out() will output to this
Simon Glass7581c012017-06-18 22:08:58 -0600160 file.
161
162 Args:
163 fname: Filename to send output to, or '-' for stdout
164 """
165 if fname == '-':
166 self._outfile = sys.stdout
167 else:
168 self._outfile = open(fname, 'w')
169
Simon Glass2be282c2017-06-18 22:08:59 -0600170 def out(self, line):
Simon Glass7581c012017-06-18 22:08:58 -0600171 """Output a string to the output file
172
173 Args:
Simon Glass2be282c2017-06-18 22:08:59 -0600174 line: String to output
Simon Glass7581c012017-06-18 22:08:58 -0600175 """
Simon Glass2be282c2017-06-18 22:08:59 -0600176 self._outfile.write(line)
Simon Glass7581c012017-06-18 22:08:58 -0600177
Simon Glass2be282c2017-06-18 22:08:59 -0600178 def buf(self, line):
Simon Glass7581c012017-06-18 22:08:58 -0600179 """Buffer up a string to send later
180
181 Args:
Simon Glass2be282c2017-06-18 22:08:59 -0600182 line: String to add to our 'buffer' list
Simon Glass7581c012017-06-18 22:08:58 -0600183 """
Simon Glass2be282c2017-06-18 22:08:59 -0600184 self._lines.append(line)
Simon Glass7581c012017-06-18 22:08:58 -0600185
Simon Glass2be282c2017-06-18 22:08:59 -0600186 def get_buf(self):
Simon Glass7581c012017-06-18 22:08:58 -0600187 """Get the contents of the output buffer, and clear it
188
189 Returns:
190 The output buffer, which is then cleared for future use
191 """
192 lines = self._lines
193 self._lines = []
194 return lines
195
Simon Glassd5031142017-08-29 14:16:01 -0600196 def out_header(self):
197 """Output a message indicating that this is an auto-generated file"""
198 self.out('''/*
199 * DO NOT MODIFY
200 *
201 * This file was generated by dtoc from a .dtb (device tree binary) file.
202 */
203
204''')
205
Simon Glass8fed2eb2017-08-29 14:15:55 -0600206 def get_phandle_argc(self, prop, node_name):
207 """Check if a node contains phandles
Simon Glass2925c262017-08-29 14:15:54 -0600208
Simon Glass8fed2eb2017-08-29 14:15:55 -0600209 We have no reliable way of detecting whether a node uses a phandle
210 or not. As an interim measure, use a list of known property names.
Simon Glass2925c262017-08-29 14:15:54 -0600211
Simon Glass8fed2eb2017-08-29 14:15:55 -0600212 Args:
213 prop: Prop object to check
214 Return:
215 Number of argument cells is this is a phandle, else None
216 """
217 if prop.name in ['clocks']:
Simon Glass760b7172018-07-06 10:27:31 -0600218 if not isinstance(prop.value, list):
219 prop.value = [prop.value]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600220 val = prop.value
Simon Glass8fed2eb2017-08-29 14:15:55 -0600221 i = 0
222
223 max_args = 0
224 args = []
225 while i < len(val):
226 phandle = fdt_util.fdt32_to_cpu(val[i])
Simon Glass760b7172018-07-06 10:27:31 -0600227 # If we get to the end of the list, stop. This can happen
228 # since some nodes have more phandles in the list than others,
229 # but we allocate enough space for the largest list. So those
230 # nodes with shorter lists end up with zeroes at the end.
231 if not phandle:
232 break
Simon Glass8fed2eb2017-08-29 14:15:55 -0600233 target = self._fdt.phandle_to_node.get(phandle)
234 if not target:
235 raise ValueError("Cannot parse '%s' in node '%s'" %
236 (prop.name, node_name))
237 prop_name = '#clock-cells'
238 cells = target.props.get(prop_name)
239 if not cells:
240 raise ValueError("Node '%s' has no '%s' property" %
241 (target.name, prop_name))
242 num_args = fdt_util.fdt32_to_cpu(cells.value)
243 max_args = max(max_args, num_args)
244 args.append(num_args)
245 i += 1 + num_args
246 return PhandleInfo(max_args, args)
247 return None
Simon Glass2925c262017-08-29 14:15:54 -0600248
Simon Glass2be282c2017-06-18 22:08:59 -0600249 def scan_dtb(self):
Anatolij Gustschinf1a7ba12017-08-18 17:58:51 +0200250 """Scan the device tree to obtain a tree of nodes and properties
Simon Glass7581c012017-06-18 22:08:58 -0600251
Simon Glass2be282c2017-06-18 22:08:59 -0600252 Once this is done, self._fdt.GetRoot() can be called to obtain the
Simon Glass7581c012017-06-18 22:08:58 -0600253 device tree root node, and progress from there.
254 """
Simon Glass2be282c2017-06-18 22:08:59 -0600255 self._fdt = fdt.FdtScan(self._dtb_fname)
Simon Glass7581c012017-06-18 22:08:58 -0600256
Simon Glass2be282c2017-06-18 22:08:59 -0600257 def scan_node(self, root):
258 """Scan a node and subnodes to build a tree of node and phandle info
259
Simon Glass72ab7c52017-08-29 14:15:53 -0600260 This adds each node to self._valid_nodes.
Simon Glass2be282c2017-06-18 22:08:59 -0600261
262 Args:
263 root: Root node for scan
264 """
Simon Glass7581c012017-06-18 22:08:58 -0600265 for node in root.subnodes:
266 if 'compatible' in node.props:
267 status = node.props.get('status')
Simon Glasse36024b2017-06-18 22:09:01 -0600268 if (not self._include_disabled and not status or
Simon Glass2be282c2017-06-18 22:08:59 -0600269 status.value != 'disabled'):
Simon Glass7581c012017-06-18 22:08:58 -0600270 self._valid_nodes.append(node)
Simon Glass7581c012017-06-18 22:08:58 -0600271
272 # recurse to handle any subnodes
Simon Glass2be282c2017-06-18 22:08:59 -0600273 self.scan_node(node)
Simon Glass7581c012017-06-18 22:08:58 -0600274
Simon Glass2be282c2017-06-18 22:08:59 -0600275 def scan_tree(self):
Simon Glass7581c012017-06-18 22:08:58 -0600276 """Scan the device tree for useful information
277
278 This fills in the following properties:
Simon Glass7581c012017-06-18 22:08:58 -0600279 _valid_nodes: A list of nodes we wish to consider include in the
280 platform data
281 """
Simon Glass7581c012017-06-18 22:08:58 -0600282 self._valid_nodes = []
Simon Glass2be282c2017-06-18 22:08:59 -0600283 return self.scan_node(self._fdt.GetRoot())
Simon Glass7581c012017-06-18 22:08:58 -0600284
Simon Glassc20ee0e2017-08-29 14:15:50 -0600285 @staticmethod
286 def get_num_cells(node):
287 """Get the number of cells in addresses and sizes for this node
288
289 Args:
290 node: Node to check
291
292 Returns:
293 Tuple:
294 Number of address cells for this node
295 Number of size cells for this node
296 """
297 parent = node.parent
298 na, ns = 2, 2
299 if parent:
300 na_prop = parent.props.get('#address-cells')
301 ns_prop = parent.props.get('#size-cells')
302 if na_prop:
303 na = fdt_util.fdt32_to_cpu(na_prop.value)
304 if ns_prop:
305 ns = fdt_util.fdt32_to_cpu(ns_prop.value)
306 return na, ns
307
308 def scan_reg_sizes(self):
309 """Scan for 64-bit 'reg' properties and update the values
310
311 This finds 'reg' properties with 64-bit data and converts the value to
312 an array of 64-values. This allows it to be output in a way that the
313 C code can read.
314 """
315 for node in self._valid_nodes:
316 reg = node.props.get('reg')
317 if not reg:
318 continue
319 na, ns = self.get_num_cells(node)
320 total = na + ns
321
322 if reg.type != fdt.TYPE_INT:
Simon Glassdfe5f5b2018-07-06 10:27:32 -0600323 raise ValueError("Node '%s' reg property is not an int" %
324 node.name)
Simon Glassc20ee0e2017-08-29 14:15:50 -0600325 if len(reg.value) % total:
326 raise ValueError("Node '%s' reg property has %d cells "
327 'which is not a multiple of na + ns = %d + %d)' %
328 (node.name, len(reg.value), na, ns))
329 reg.na = na
330 reg.ns = ns
331 if na != 1 or ns != 1:
332 reg.type = fdt.TYPE_INT64
333 i = 0
334 new_value = []
335 val = reg.value
336 if not isinstance(val, list):
337 val = [val]
338 while i < len(val):
339 addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
340 i += na
341 size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
342 i += ns
343 new_value += [addr, size]
344 reg.value = new_value
345
Simon Glass2be282c2017-06-18 22:08:59 -0600346 def scan_structs(self):
Simon Glass7581c012017-06-18 22:08:58 -0600347 """Scan the device tree building up the C structures we will use.
348
349 Build a dict keyed by C struct name containing a dict of Prop
350 object for each struct field (keyed by property name). Where the
351 same struct appears multiple times, try to use the 'widest'
352 property, i.e. the one with a type which can express all others.
353
354 Once the widest property is determined, all other properties are
355 updated to match that width.
356 """
357 structs = {}
358 for node in self._valid_nodes:
Simon Glass56e0bbe2017-06-18 22:09:02 -0600359 node_name, _ = get_compat_name(node)
Simon Glass7581c012017-06-18 22:08:58 -0600360 fields = {}
361
362 # Get a list of all the valid properties in this node.
363 for name, prop in node.props.items():
364 if name not in PROP_IGNORE_LIST and name[0] != '#':
365 fields[name] = copy.deepcopy(prop)
366
367 # If we've seen this node_name before, update the existing struct.
368 if node_name in structs:
369 struct = structs[node_name]
370 for name, prop in fields.items():
371 oldprop = struct.get(name)
372 if oldprop:
373 oldprop.Widen(prop)
374 else:
375 struct[name] = prop
376
377 # Otherwise store this as a new struct.
378 else:
379 structs[node_name] = fields
380
381 upto = 0
382 for node in self._valid_nodes:
Simon Glass56e0bbe2017-06-18 22:09:02 -0600383 node_name, _ = get_compat_name(node)
Simon Glass7581c012017-06-18 22:08:58 -0600384 struct = structs[node_name]
385 for name, prop in node.props.items():
386 if name not in PROP_IGNORE_LIST and name[0] != '#':
387 prop.Widen(struct[name])
388 upto += 1
389
Simon Glass56e0bbe2017-06-18 22:09:02 -0600390 struct_name, aliases = get_compat_name(node)
Simon Glass7581c012017-06-18 22:08:58 -0600391 for alias in aliases:
392 self._aliases[alias] = struct_name
393
394 return structs
395
Simon Glass2be282c2017-06-18 22:08:59 -0600396 def scan_phandles(self):
Simon Glass7581c012017-06-18 22:08:58 -0600397 """Figure out what phandles each node uses
398
399 We need to be careful when outputing nodes that use phandles since
400 they must come after the declaration of the phandles in the C file.
401 Otherwise we get a compiler error since the phandle struct is not yet
402 declared.
403
404 This function adds to each node a list of phandle nodes that the node
405 depends on. This allows us to output things in the right order.
406 """
407 for node in self._valid_nodes:
408 node.phandles = set()
409 for pname, prop in node.props.items():
410 if pname in PROP_IGNORE_LIST or pname[0] == '#':
411 continue
Simon Glass8fed2eb2017-08-29 14:15:55 -0600412 info = self.get_phandle_argc(prop, node.name)
413 if info:
Simon Glass8fed2eb2017-08-29 14:15:55 -0600414 # Process the list as pairs of (phandle, id)
Simon Glass634eba42017-08-29 14:15:59 -0600415 pos = 0
416 for args in info.args:
417 phandle_cell = prop.value[pos]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600418 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
419 target_node = self._fdt.phandle_to_node[phandle]
420 node.phandles.add(target_node)
Simon Glass634eba42017-08-29 14:15:59 -0600421 pos += 1 + args
Simon Glass7581c012017-06-18 22:08:58 -0600422
423
Simon Glass2be282c2017-06-18 22:08:59 -0600424 def generate_structs(self, structs):
Simon Glass7581c012017-06-18 22:08:58 -0600425 """Generate struct defintions for the platform data
426
427 This writes out the body of a header file consisting of structure
428 definitions for node in self._valid_nodes. See the documentation in
Heinrich Schuchardt2799a692020-02-25 21:35:39 +0100429 doc/driver-model/of-plat.rst for more information.
Simon Glass7581c012017-06-18 22:08:58 -0600430 """
Simon Glassd5031142017-08-29 14:16:01 -0600431 self.out_header()
Simon Glass2be282c2017-06-18 22:08:59 -0600432 self.out('#include <stdbool.h>\n')
Masahiro Yamadab08c8c42018-03-05 01:20:11 +0900433 self.out('#include <linux/libfdt.h>\n')
Simon Glass7581c012017-06-18 22:08:58 -0600434
435 # Output the struct definition
436 for name in sorted(structs):
Simon Glass2be282c2017-06-18 22:08:59 -0600437 self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
Simon Glass7581c012017-06-18 22:08:58 -0600438 for pname in sorted(structs[name]):
439 prop = structs[name][pname]
Simon Glass8fed2eb2017-08-29 14:15:55 -0600440 info = self.get_phandle_argc(prop, structs[name])
441 if info:
Simon Glass7581c012017-06-18 22:08:58 -0600442 # For phandles, include a reference to the target
Simon Glass0d154632017-08-29 14:15:56 -0600443 struct_name = 'struct phandle_%d_arg' % info.max_args
444 self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
Simon Glass2be282c2017-06-18 22:08:59 -0600445 conv_name_to_c(prop.name),
Simon Glass634eba42017-08-29 14:15:59 -0600446 len(info.args)))
Simon Glass7581c012017-06-18 22:08:58 -0600447 else:
448 ptype = TYPE_NAMES[prop.type]
Simon Glass2be282c2017-06-18 22:08:59 -0600449 self.out('\t%s%s' % (tab_to(2, ptype),
450 conv_name_to_c(prop.name)))
451 if isinstance(prop.value, list):
452 self.out('[%d]' % len(prop.value))
453 self.out(';\n')
454 self.out('};\n')
Simon Glass7581c012017-06-18 22:08:58 -0600455
Simon Glass90a81322019-05-17 22:00:31 -0600456 for alias, struct_name in self._aliases.items():
Heiko Schochere9cde872019-04-16 13:31:58 +0200457 if alias not in sorted(structs):
458 self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
459 STRUCT_PREFIX, struct_name))
Simon Glass7581c012017-06-18 22:08:58 -0600460
Simon Glass2be282c2017-06-18 22:08:59 -0600461 def output_node(self, node):
Simon Glass7581c012017-06-18 22:08:58 -0600462 """Output the C code for a node
463
464 Args:
465 node: node to output
466 """
Simon Glass56e0bbe2017-06-18 22:09:02 -0600467 struct_name, _ = get_compat_name(node)
Simon Glass2be282c2017-06-18 22:08:59 -0600468 var_name = conv_name_to_c(node.name)
Simon Goldschmidt7d05d3a2019-01-07 20:29:26 +0100469 self.buf('static const struct %s%s %s%s = {\n' %
Simon Glass2be282c2017-06-18 22:08:59 -0600470 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
Simon Glass1953ce72019-05-17 22:00:32 -0600471 for pname in sorted(node.props):
472 prop = node.props[pname]
Simon Glass7581c012017-06-18 22:08:58 -0600473 if pname in PROP_IGNORE_LIST or pname[0] == '#':
474 continue
Simon Glass2be282c2017-06-18 22:08:59 -0600475 member_name = conv_name_to_c(prop.name)
476 self.buf('\t%s= ' % tab_to(3, '.' + member_name))
Simon Glass7581c012017-06-18 22:08:58 -0600477
478 # Special handling for lists
Simon Glass2be282c2017-06-18 22:08:59 -0600479 if isinstance(prop.value, list):
480 self.buf('{')
Simon Glass7581c012017-06-18 22:08:58 -0600481 vals = []
482 # For phandles, output a reference to the platform data
483 # of the target node.
Simon Glass8fed2eb2017-08-29 14:15:55 -0600484 info = self.get_phandle_argc(prop, node.name)
485 if info:
Simon Glass7581c012017-06-18 22:08:58 -0600486 # Process the list as pairs of (phandle, id)
Simon Glass634eba42017-08-29 14:15:59 -0600487 pos = 0
488 for args in info.args:
489 phandle_cell = prop.value[pos]
Simon Glass7581c012017-06-18 22:08:58 -0600490 phandle = fdt_util.fdt32_to_cpu(phandle_cell)
Simon Glass72ab7c52017-08-29 14:15:53 -0600491 target_node = self._fdt.phandle_to_node[phandle]
Simon Glass2be282c2017-06-18 22:08:59 -0600492 name = conv_name_to_c(target_node.name)
Simon Glass634eba42017-08-29 14:15:59 -0600493 arg_values = []
494 for i in range(args):
495 arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
496 pos += 1 + args
497 vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
498 ', '.join(arg_values)))
Simon Glass35d50372017-08-29 14:15:57 -0600499 for val in vals:
500 self.buf('\n\t\t%s,' % val)
Simon Glass7581c012017-06-18 22:08:58 -0600501 else:
502 for val in prop.value:
Simon Glass56e0bbe2017-06-18 22:09:02 -0600503 vals.append(get_value(prop.type, val))
Simon Glass21d54ac2017-08-29 14:15:49 -0600504
Simon Glass35d50372017-08-29 14:15:57 -0600505 # Put 8 values per line to avoid very long lines.
Simon Glass90a81322019-05-17 22:00:31 -0600506 for i in range(0, len(vals), 8):
Simon Glass35d50372017-08-29 14:15:57 -0600507 if i:
508 self.buf(',\n\t\t')
509 self.buf(', '.join(vals[i:i + 8]))
Simon Glass2be282c2017-06-18 22:08:59 -0600510 self.buf('}')
Simon Glass7581c012017-06-18 22:08:58 -0600511 else:
Simon Glass56e0bbe2017-06-18 22:09:02 -0600512 self.buf(get_value(prop.type, prop.value))
Simon Glass2be282c2017-06-18 22:08:59 -0600513 self.buf(',\n')
514 self.buf('};\n')
Simon Glass7581c012017-06-18 22:08:58 -0600515
516 # Add a device declaration
Simon Glass2be282c2017-06-18 22:08:59 -0600517 self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
518 self.buf('\t.name\t\t= "%s",\n' % struct_name)
519 self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
520 self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
521 self.buf('};\n')
522 self.buf('\n')
Simon Glass7581c012017-06-18 22:08:58 -0600523
Simon Glass2be282c2017-06-18 22:08:59 -0600524 self.out(''.join(self.get_buf()))
Simon Glass7581c012017-06-18 22:08:58 -0600525
Simon Glass2be282c2017-06-18 22:08:59 -0600526 def generate_tables(self):
Simon Glass7581c012017-06-18 22:08:58 -0600527 """Generate device defintions for the platform data
528
529 This writes out C platform data initialisation data and
530 U_BOOT_DEVICE() declarations for each valid node. Where a node has
531 multiple compatible strings, a #define is used to make them equivalent.
532
Heinrich Schuchardt2799a692020-02-25 21:35:39 +0100533 See the documentation in doc/driver-model/of-plat.rst for more
Simon Glass7581c012017-06-18 22:08:58 -0600534 information.
535 """
Simon Glassd5031142017-08-29 14:16:01 -0600536 self.out_header()
Simon Glass2be282c2017-06-18 22:08:59 -0600537 self.out('#include <common.h>\n')
538 self.out('#include <dm.h>\n')
539 self.out('#include <dt-structs.h>\n')
540 self.out('\n')
Simon Glass7581c012017-06-18 22:08:58 -0600541 nodes_to_output = list(self._valid_nodes)
542
543 # Keep outputing nodes until there is none left
544 while nodes_to_output:
545 node = nodes_to_output[0]
546 # Output all the node's dependencies first
547 for req_node in node.phandles:
548 if req_node in nodes_to_output:
Simon Glass2be282c2017-06-18 22:08:59 -0600549 self.output_node(req_node)
Simon Glass7581c012017-06-18 22:08:58 -0600550 nodes_to_output.remove(req_node)
Simon Glass2be282c2017-06-18 22:08:59 -0600551 self.output_node(node)
Simon Glass7581c012017-06-18 22:08:58 -0600552 nodes_to_output.remove(node)
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600553
554
555def run_steps(args, dtb_file, include_disabled, output):
556 """Run all the steps of the dtoc tool
557
558 Args:
559 args: List of non-option arguments provided to the problem
560 dtb_file: Filename of dtb file to process
561 include_disabled: True to include disabled nodes
562 output: Name of output file
563 """
564 if not args:
565 raise ValueError('Please specify a command: struct, platdata')
566
567 plat = DtbPlatdata(dtb_file, include_disabled)
568 plat.scan_dtb()
569 plat.scan_tree()
Simon Glassc20ee0e2017-08-29 14:15:50 -0600570 plat.scan_reg_sizes()
Simon Glassfa0ea5b2017-06-18 22:09:03 -0600571 plat.setup_output(output)
572 structs = plat.scan_structs()
573 plat.scan_phandles()
574
575 for cmd in args[0].split(','):
576 if cmd == 'struct':
577 plat.generate_structs(structs)
578 elif cmd == 'platdata':
579 plat.generate_tables()
580 else:
581 raise ValueError("Unknown command '%s': (use: struct, platdata)" %
582 cmd)