17581c01aSSimon Glass#!/usr/bin/python 27581c01aSSimon Glass# 37581c01aSSimon Glass# Copyright (C) 2017 Google, Inc 47581c01aSSimon Glass# Written by Simon Glass <sjg@chromium.org> 57581c01aSSimon Glass# 67581c01aSSimon Glass# SPDX-License-Identifier: GPL-2.0+ 77581c01aSSimon Glass# 87581c01aSSimon Glass 92be282caSSimon Glass"""Device tree to platform data class 102be282caSSimon Glass 112be282caSSimon GlassThis supports converting device tree data to C structures definitions and 122be282caSSimon Glassstatic data. 132be282caSSimon Glass""" 142be282caSSimon Glass 15*cb3f9bf4SSimon Glassimport collections 167581c01aSSimon Glassimport copy 172be282caSSimon Glassimport sys 187581c01aSSimon Glass 197581c01aSSimon Glassimport fdt 207581c01aSSimon Glassimport fdt_util 217581c01aSSimon Glass 227581c01aSSimon Glass# When we see these properties we ignore them - i.e. do not create a structure member 237581c01aSSimon GlassPROP_IGNORE_LIST = [ 247581c01aSSimon Glass '#address-cells', 257581c01aSSimon Glass '#gpio-cells', 267581c01aSSimon Glass '#size-cells', 277581c01aSSimon Glass 'compatible', 287581c01aSSimon Glass 'linux,phandle', 297581c01aSSimon Glass "status", 307581c01aSSimon Glass 'phandle', 317581c01aSSimon Glass 'u-boot,dm-pre-reloc', 327581c01aSSimon Glass 'u-boot,dm-tpl', 337581c01aSSimon Glass 'u-boot,dm-spl', 347581c01aSSimon Glass] 357581c01aSSimon Glass 367581c01aSSimon Glass# C type declarations for the tyues we support 377581c01aSSimon GlassTYPE_NAMES = { 387581c01aSSimon Glass fdt.TYPE_INT: 'fdt32_t', 397581c01aSSimon Glass fdt.TYPE_BYTE: 'unsigned char', 407581c01aSSimon Glass fdt.TYPE_STRING: 'const char *', 417581c01aSSimon Glass fdt.TYPE_BOOL: 'bool', 42ef2715f4SSimon Glass fdt.TYPE_INT64: 'fdt64_t', 432be282caSSimon Glass} 447581c01aSSimon Glass 457581c01aSSimon GlassSTRUCT_PREFIX = 'dtd_' 467581c01aSSimon GlassVAL_PREFIX = 'dtv_' 477581c01aSSimon Glass 48*cb3f9bf4SSimon Glass# This holds information about a property which includes phandles. 49*cb3f9bf4SSimon Glass# 50*cb3f9bf4SSimon Glass# max_args: integer: Maximum number or arguments that any phandle uses (int). 51*cb3f9bf4SSimon Glass# args: Number of args for each phandle in the property. The total number of 52*cb3f9bf4SSimon Glass# phandles is len(args). This is a list of integers. 53*cb3f9bf4SSimon GlassPhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args']) 54*cb3f9bf4SSimon Glass 55*cb3f9bf4SSimon Glass 562be282caSSimon Glassdef conv_name_to_c(name): 577581c01aSSimon Glass """Convert a device-tree name to a C identifier 587581c01aSSimon Glass 5930107b08SSimon Glass This uses multiple replace() calls instead of re.sub() since it is faster 6030107b08SSimon Glass (400ms for 1m calls versus 1000ms for the 're' version). 6130107b08SSimon Glass 627581c01aSSimon Glass Args: 637581c01aSSimon Glass name: Name to convert 647581c01aSSimon Glass Return: 657581c01aSSimon Glass String containing the C version of this name 667581c01aSSimon Glass """ 672be282caSSimon Glass new = name.replace('@', '_at_') 682be282caSSimon Glass new = new.replace('-', '_') 692be282caSSimon Glass new = new.replace(',', '_') 702be282caSSimon Glass new = new.replace('.', '_') 712be282caSSimon Glass return new 727581c01aSSimon Glass 732be282caSSimon Glassdef tab_to(num_tabs, line): 742be282caSSimon Glass """Append tabs to a line of text to reach a tab stop. 757581c01aSSimon Glass 762be282caSSimon Glass Args: 772be282caSSimon Glass num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.) 782be282caSSimon Glass line: Line of text to append to 792be282caSSimon Glass 802be282caSSimon Glass Returns: 812be282caSSimon Glass line with the correct number of tabs appeneded. If the line already 822be282caSSimon Glass extends past that tab stop then a single space is appended. 832be282caSSimon Glass """ 842be282caSSimon Glass if len(line) >= num_tabs * 8: 852be282caSSimon Glass return line + ' ' 862be282caSSimon Glass return line + '\t' * (num_tabs - len(line) // 8) 872be282caSSimon Glass 8856e0bbe0SSimon Glassdef get_value(ftype, value): 8956e0bbe0SSimon Glass """Get a value as a C expression 9056e0bbe0SSimon Glass 9156e0bbe0SSimon Glass For integers this returns a byte-swapped (little-endian) hex string 9256e0bbe0SSimon Glass For bytes this returns a hex string, e.g. 0x12 9356e0bbe0SSimon Glass For strings this returns a literal string enclosed in quotes 9456e0bbe0SSimon Glass For booleans this return 'true' 9556e0bbe0SSimon Glass 9656e0bbe0SSimon Glass Args: 9756e0bbe0SSimon Glass type: Data type (fdt_util) 9856e0bbe0SSimon Glass value: Data value, as a string of bytes 9956e0bbe0SSimon Glass """ 10056e0bbe0SSimon Glass if ftype == fdt.TYPE_INT: 10156e0bbe0SSimon Glass return '%#x' % fdt_util.fdt32_to_cpu(value) 10256e0bbe0SSimon Glass elif ftype == fdt.TYPE_BYTE: 10356e0bbe0SSimon Glass return '%#x' % ord(value[0]) 10456e0bbe0SSimon Glass elif ftype == fdt.TYPE_STRING: 10556e0bbe0SSimon Glass return '"%s"' % value 10656e0bbe0SSimon Glass elif ftype == fdt.TYPE_BOOL: 10756e0bbe0SSimon Glass return 'true' 108ef2715f4SSimon Glass elif ftype == fdt.TYPE_INT64: 109ef2715f4SSimon Glass return '%#x' % value 11056e0bbe0SSimon Glass 11156e0bbe0SSimon Glassdef get_compat_name(node): 11256e0bbe0SSimon Glass """Get a node's first compatible string as a C identifier 11356e0bbe0SSimon Glass 11456e0bbe0SSimon Glass Args: 11556e0bbe0SSimon Glass node: Node object to check 11656e0bbe0SSimon Glass Return: 11756e0bbe0SSimon Glass Tuple: 11856e0bbe0SSimon Glass C identifier for the first compatible string 11956e0bbe0SSimon Glass List of C identifiers for all the other compatible strings 12056e0bbe0SSimon Glass (possibly empty) 12156e0bbe0SSimon Glass """ 12256e0bbe0SSimon Glass compat = node.props['compatible'].value 12356e0bbe0SSimon Glass aliases = [] 12456e0bbe0SSimon Glass if isinstance(compat, list): 12556e0bbe0SSimon Glass compat, aliases = compat[0], compat[1:] 12656e0bbe0SSimon Glass return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases] 12756e0bbe0SSimon Glass 12856e0bbe0SSimon Glass 1292be282caSSimon Glassclass DtbPlatdata(object): 1307581c01aSSimon Glass """Provide a means to convert device tree binary data to platform data 1317581c01aSSimon Glass 1327581c01aSSimon Glass The output of this process is C structures which can be used in space- 1337581c01aSSimon Glass constrained encvironments where the ~3KB code overhead of device tree 1347581c01aSSimon Glass code is not affordable. 1357581c01aSSimon Glass 1367581c01aSSimon Glass Properties: 1372be282caSSimon Glass _fdt: Fdt object, referencing the device tree 1387581c01aSSimon Glass _dtb_fname: Filename of the input device tree binary file 1397581c01aSSimon Glass _valid_nodes: A list of Node object with compatible strings 140e36024b0SSimon Glass _include_disabled: true to include nodes marked status = "disabled" 1417581c01aSSimon Glass _outfile: The current output file (sys.stdout or a real file) 1427581c01aSSimon Glass _lines: Stashed list of output lines for outputting in the future 1437581c01aSSimon Glass """ 144e36024b0SSimon Glass def __init__(self, dtb_fname, include_disabled): 1452be282caSSimon Glass self._fdt = None 1467581c01aSSimon Glass self._dtb_fname = dtb_fname 1477581c01aSSimon Glass self._valid_nodes = None 148e36024b0SSimon Glass self._include_disabled = include_disabled 1497581c01aSSimon Glass self._outfile = None 1507581c01aSSimon Glass self._lines = [] 1517581c01aSSimon Glass self._aliases = {} 1527581c01aSSimon Glass 1532be282caSSimon Glass def setup_output(self, fname): 1547581c01aSSimon Glass """Set up the output destination 1557581c01aSSimon Glass 1562be282caSSimon Glass Once this is done, future calls to self.out() will output to this 1577581c01aSSimon Glass file. 1587581c01aSSimon Glass 1597581c01aSSimon Glass Args: 1607581c01aSSimon Glass fname: Filename to send output to, or '-' for stdout 1617581c01aSSimon Glass """ 1627581c01aSSimon Glass if fname == '-': 1637581c01aSSimon Glass self._outfile = sys.stdout 1647581c01aSSimon Glass else: 1657581c01aSSimon Glass self._outfile = open(fname, 'w') 1667581c01aSSimon Glass 1672be282caSSimon Glass def out(self, line): 1687581c01aSSimon Glass """Output a string to the output file 1697581c01aSSimon Glass 1707581c01aSSimon Glass Args: 1712be282caSSimon Glass line: String to output 1727581c01aSSimon Glass """ 1732be282caSSimon Glass self._outfile.write(line) 1747581c01aSSimon Glass 1752be282caSSimon Glass def buf(self, line): 1767581c01aSSimon Glass """Buffer up a string to send later 1777581c01aSSimon Glass 1787581c01aSSimon Glass Args: 1792be282caSSimon Glass line: String to add to our 'buffer' list 1807581c01aSSimon Glass """ 1812be282caSSimon Glass self._lines.append(line) 1827581c01aSSimon Glass 1832be282caSSimon Glass def get_buf(self): 1847581c01aSSimon Glass """Get the contents of the output buffer, and clear it 1857581c01aSSimon Glass 1867581c01aSSimon Glass Returns: 1877581c01aSSimon Glass The output buffer, which is then cleared for future use 1887581c01aSSimon Glass """ 1897581c01aSSimon Glass lines = self._lines 1907581c01aSSimon Glass self._lines = [] 1917581c01aSSimon Glass return lines 1927581c01aSSimon Glass 193*cb3f9bf4SSimon Glass def get_phandle_argc(self, prop, node_name): 1947088d44bSSimon Glass """Check if a node contains phandles 1957088d44bSSimon Glass 1967088d44bSSimon Glass We have no reliable way of detecting whether a node uses a phandle 1977088d44bSSimon Glass or not. As an interim measure, use a list of known property names. 1987088d44bSSimon Glass 1997088d44bSSimon Glass Args: 2007088d44bSSimon Glass prop: Prop object to check 2017088d44bSSimon Glass Return: 202*cb3f9bf4SSimon Glass Number of argument cells is this is a phandle, else None 2037088d44bSSimon Glass """ 2047088d44bSSimon Glass if prop.name in ['clocks']: 205*cb3f9bf4SSimon Glass val = prop.value 206*cb3f9bf4SSimon Glass if not isinstance(val, list): 207*cb3f9bf4SSimon Glass val = [val] 208*cb3f9bf4SSimon Glass i = 0 209*cb3f9bf4SSimon Glass 210*cb3f9bf4SSimon Glass max_args = 0 211*cb3f9bf4SSimon Glass args = [] 212*cb3f9bf4SSimon Glass while i < len(val): 213*cb3f9bf4SSimon Glass phandle = fdt_util.fdt32_to_cpu(val[i]) 214*cb3f9bf4SSimon Glass target = self._fdt.phandle_to_node.get(phandle) 215*cb3f9bf4SSimon Glass if not target: 216*cb3f9bf4SSimon Glass raise ValueError("Cannot parse '%s' in node '%s'" % 217*cb3f9bf4SSimon Glass (prop.name, node_name)) 218*cb3f9bf4SSimon Glass prop_name = '#clock-cells' 219*cb3f9bf4SSimon Glass cells = target.props.get(prop_name) 220*cb3f9bf4SSimon Glass if not cells: 221*cb3f9bf4SSimon Glass raise ValueError("Node '%s' has no '%s' property" % 222*cb3f9bf4SSimon Glass (target.name, prop_name)) 223*cb3f9bf4SSimon Glass num_args = fdt_util.fdt32_to_cpu(cells.value) 224*cb3f9bf4SSimon Glass max_args = max(max_args, num_args) 225*cb3f9bf4SSimon Glass args.append(num_args) 226*cb3f9bf4SSimon Glass i += 1 + num_args 227*cb3f9bf4SSimon Glass return PhandleInfo(max_args, args) 228*cb3f9bf4SSimon Glass return None 2297088d44bSSimon Glass 2302be282caSSimon Glass def scan_dtb(self): 231f1a7ba1dSAnatolij Gustschin """Scan the device tree to obtain a tree of nodes and properties 2327581c01aSSimon Glass 2332be282caSSimon Glass Once this is done, self._fdt.GetRoot() can be called to obtain the 2347581c01aSSimon Glass device tree root node, and progress from there. 2357581c01aSSimon Glass """ 2362be282caSSimon Glass self._fdt = fdt.FdtScan(self._dtb_fname) 2377581c01aSSimon Glass 2382be282caSSimon Glass def scan_node(self, root): 2392be282caSSimon Glass """Scan a node and subnodes to build a tree of node and phandle info 2402be282caSSimon Glass 2410ac13c21SSimon Glass This adds each node to self._valid_nodes. 2422be282caSSimon Glass 2432be282caSSimon Glass Args: 2442be282caSSimon Glass root: Root node for scan 2452be282caSSimon Glass """ 2467581c01aSSimon Glass for node in root.subnodes: 2477581c01aSSimon Glass if 'compatible' in node.props: 2487581c01aSSimon Glass status = node.props.get('status') 249e36024b0SSimon Glass if (not self._include_disabled and not status or 2507581c01aSSimon Glass status.value != 'disabled'): 2517581c01aSSimon Glass self._valid_nodes.append(node) 2527581c01aSSimon Glass 2537581c01aSSimon Glass # recurse to handle any subnodes 2542be282caSSimon Glass self.scan_node(node) 2557581c01aSSimon Glass 2562be282caSSimon Glass def scan_tree(self): 2577581c01aSSimon Glass """Scan the device tree for useful information 2587581c01aSSimon Glass 2597581c01aSSimon Glass This fills in the following properties: 2607581c01aSSimon Glass _valid_nodes: A list of nodes we wish to consider include in the 2617581c01aSSimon Glass platform data 2627581c01aSSimon Glass """ 2637581c01aSSimon Glass self._valid_nodes = [] 2642be282caSSimon Glass return self.scan_node(self._fdt.GetRoot()) 2657581c01aSSimon Glass 266a28bfcc3SSimon Glass @staticmethod 267a28bfcc3SSimon Glass def get_num_cells(node): 268a28bfcc3SSimon Glass """Get the number of cells in addresses and sizes for this node 269a28bfcc3SSimon Glass 270a28bfcc3SSimon Glass Args: 271a28bfcc3SSimon Glass node: Node to check 272a28bfcc3SSimon Glass 273a28bfcc3SSimon Glass Returns: 274a28bfcc3SSimon Glass Tuple: 275a28bfcc3SSimon Glass Number of address cells for this node 276a28bfcc3SSimon Glass Number of size cells for this node 277a28bfcc3SSimon Glass """ 278a28bfcc3SSimon Glass parent = node.parent 279a28bfcc3SSimon Glass na, ns = 2, 2 280a28bfcc3SSimon Glass if parent: 281a28bfcc3SSimon Glass na_prop = parent.props.get('#address-cells') 282a28bfcc3SSimon Glass ns_prop = parent.props.get('#size-cells') 283a28bfcc3SSimon Glass if na_prop: 284a28bfcc3SSimon Glass na = fdt_util.fdt32_to_cpu(na_prop.value) 285a28bfcc3SSimon Glass if ns_prop: 286a28bfcc3SSimon Glass ns = fdt_util.fdt32_to_cpu(ns_prop.value) 287a28bfcc3SSimon Glass return na, ns 288a28bfcc3SSimon Glass 289a28bfcc3SSimon Glass def scan_reg_sizes(self): 290a28bfcc3SSimon Glass """Scan for 64-bit 'reg' properties and update the values 291a28bfcc3SSimon Glass 292a28bfcc3SSimon Glass This finds 'reg' properties with 64-bit data and converts the value to 293a28bfcc3SSimon Glass an array of 64-values. This allows it to be output in a way that the 294a28bfcc3SSimon Glass C code can read. 295a28bfcc3SSimon Glass """ 296a28bfcc3SSimon Glass for node in self._valid_nodes: 297a28bfcc3SSimon Glass reg = node.props.get('reg') 298a28bfcc3SSimon Glass if not reg: 299a28bfcc3SSimon Glass continue 300a28bfcc3SSimon Glass na, ns = self.get_num_cells(node) 301a28bfcc3SSimon Glass total = na + ns 302a28bfcc3SSimon Glass 303a28bfcc3SSimon Glass if reg.type != fdt.TYPE_INT: 304a28bfcc3SSimon Glass raise ValueError("Node '%s' reg property is not an int") 305a28bfcc3SSimon Glass if len(reg.value) % total: 306a28bfcc3SSimon Glass raise ValueError("Node '%s' reg property has %d cells " 307a28bfcc3SSimon Glass 'which is not a multiple of na + ns = %d + %d)' % 308a28bfcc3SSimon Glass (node.name, len(reg.value), na, ns)) 309a28bfcc3SSimon Glass reg.na = na 310a28bfcc3SSimon Glass reg.ns = ns 311a28bfcc3SSimon Glass if na != 1 or ns != 1: 312a28bfcc3SSimon Glass reg.type = fdt.TYPE_INT64 313a28bfcc3SSimon Glass i = 0 314a28bfcc3SSimon Glass new_value = [] 315a28bfcc3SSimon Glass val = reg.value 316a28bfcc3SSimon Glass if not isinstance(val, list): 317a28bfcc3SSimon Glass val = [val] 318a28bfcc3SSimon Glass while i < len(val): 319a28bfcc3SSimon Glass addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na) 320a28bfcc3SSimon Glass i += na 321a28bfcc3SSimon Glass size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns) 322a28bfcc3SSimon Glass i += ns 323a28bfcc3SSimon Glass new_value += [addr, size] 324a28bfcc3SSimon Glass reg.value = new_value 325a28bfcc3SSimon Glass 3262be282caSSimon Glass def scan_structs(self): 3277581c01aSSimon Glass """Scan the device tree building up the C structures we will use. 3287581c01aSSimon Glass 3297581c01aSSimon Glass Build a dict keyed by C struct name containing a dict of Prop 3307581c01aSSimon Glass object for each struct field (keyed by property name). Where the 3317581c01aSSimon Glass same struct appears multiple times, try to use the 'widest' 3327581c01aSSimon Glass property, i.e. the one with a type which can express all others. 3337581c01aSSimon Glass 3347581c01aSSimon Glass Once the widest property is determined, all other properties are 3357581c01aSSimon Glass updated to match that width. 3367581c01aSSimon Glass """ 3377581c01aSSimon Glass structs = {} 3387581c01aSSimon Glass for node in self._valid_nodes: 33956e0bbe0SSimon Glass node_name, _ = get_compat_name(node) 3407581c01aSSimon Glass fields = {} 3417581c01aSSimon Glass 3427581c01aSSimon Glass # Get a list of all the valid properties in this node. 3437581c01aSSimon Glass for name, prop in node.props.items(): 3447581c01aSSimon Glass if name not in PROP_IGNORE_LIST and name[0] != '#': 3457581c01aSSimon Glass fields[name] = copy.deepcopy(prop) 3467581c01aSSimon Glass 3477581c01aSSimon Glass # If we've seen this node_name before, update the existing struct. 3487581c01aSSimon Glass if node_name in structs: 3497581c01aSSimon Glass struct = structs[node_name] 3507581c01aSSimon Glass for name, prop in fields.items(): 3517581c01aSSimon Glass oldprop = struct.get(name) 3527581c01aSSimon Glass if oldprop: 3537581c01aSSimon Glass oldprop.Widen(prop) 3547581c01aSSimon Glass else: 3557581c01aSSimon Glass struct[name] = prop 3567581c01aSSimon Glass 3577581c01aSSimon Glass # Otherwise store this as a new struct. 3587581c01aSSimon Glass else: 3597581c01aSSimon Glass structs[node_name] = fields 3607581c01aSSimon Glass 3617581c01aSSimon Glass upto = 0 3627581c01aSSimon Glass for node in self._valid_nodes: 36356e0bbe0SSimon Glass node_name, _ = get_compat_name(node) 3647581c01aSSimon Glass struct = structs[node_name] 3657581c01aSSimon Glass for name, prop in node.props.items(): 3667581c01aSSimon Glass if name not in PROP_IGNORE_LIST and name[0] != '#': 3677581c01aSSimon Glass prop.Widen(struct[name]) 3687581c01aSSimon Glass upto += 1 3697581c01aSSimon Glass 37056e0bbe0SSimon Glass struct_name, aliases = get_compat_name(node) 3717581c01aSSimon Glass for alias in aliases: 3727581c01aSSimon Glass self._aliases[alias] = struct_name 3737581c01aSSimon Glass 3747581c01aSSimon Glass return structs 3757581c01aSSimon Glass 3762be282caSSimon Glass def scan_phandles(self): 3777581c01aSSimon Glass """Figure out what phandles each node uses 3787581c01aSSimon Glass 3797581c01aSSimon Glass We need to be careful when outputing nodes that use phandles since 3807581c01aSSimon Glass they must come after the declaration of the phandles in the C file. 3817581c01aSSimon Glass Otherwise we get a compiler error since the phandle struct is not yet 3827581c01aSSimon Glass declared. 3837581c01aSSimon Glass 3847581c01aSSimon Glass This function adds to each node a list of phandle nodes that the node 3857581c01aSSimon Glass depends on. This allows us to output things in the right order. 3867581c01aSSimon Glass """ 3877581c01aSSimon Glass for node in self._valid_nodes: 3887581c01aSSimon Glass node.phandles = set() 3897581c01aSSimon Glass for pname, prop in node.props.items(): 3907581c01aSSimon Glass if pname in PROP_IGNORE_LIST or pname[0] == '#': 3917581c01aSSimon Glass continue 392*cb3f9bf4SSimon Glass info = self.get_phandle_argc(prop, node.name) 393*cb3f9bf4SSimon Glass if info: 394*cb3f9bf4SSimon Glass if not isinstance(prop.value, list): 395*cb3f9bf4SSimon Glass prop.value = [prop.value] 3967581c01aSSimon Glass # Process the list as pairs of (phandle, id) 3972be282caSSimon Glass value_it = iter(prop.value) 3982be282caSSimon Glass for phandle_cell, _ in zip(value_it, value_it): 3997581c01aSSimon Glass phandle = fdt_util.fdt32_to_cpu(phandle_cell) 4000ac13c21SSimon Glass target_node = self._fdt.phandle_to_node[phandle] 4017581c01aSSimon Glass node.phandles.add(target_node) 4027581c01aSSimon Glass 4037581c01aSSimon Glass 4042be282caSSimon Glass def generate_structs(self, structs): 4057581c01aSSimon Glass """Generate struct defintions for the platform data 4067581c01aSSimon Glass 4077581c01aSSimon Glass This writes out the body of a header file consisting of structure 4087581c01aSSimon Glass definitions for node in self._valid_nodes. See the documentation in 4097581c01aSSimon Glass README.of-plat for more information. 4107581c01aSSimon Glass """ 4112be282caSSimon Glass self.out('#include <stdbool.h>\n') 4122be282caSSimon Glass self.out('#include <libfdt.h>\n') 4137581c01aSSimon Glass 4147581c01aSSimon Glass # Output the struct definition 4157581c01aSSimon Glass for name in sorted(structs): 4162be282caSSimon Glass self.out('struct %s%s {\n' % (STRUCT_PREFIX, name)) 4177581c01aSSimon Glass for pname in sorted(structs[name]): 4187581c01aSSimon Glass prop = structs[name][pname] 419*cb3f9bf4SSimon Glass info = self.get_phandle_argc(prop, structs[name]) 420*cb3f9bf4SSimon Glass if info: 4217581c01aSSimon Glass # For phandles, include a reference to the target 4222be282caSSimon Glass self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'), 4232be282caSSimon Glass conv_name_to_c(prop.name), 4247581c01aSSimon Glass len(prop.value) / 2)) 4257581c01aSSimon Glass else: 4267581c01aSSimon Glass ptype = TYPE_NAMES[prop.type] 4272be282caSSimon Glass self.out('\t%s%s' % (tab_to(2, ptype), 4282be282caSSimon Glass conv_name_to_c(prop.name))) 4292be282caSSimon Glass if isinstance(prop.value, list): 4302be282caSSimon Glass self.out('[%d]' % len(prop.value)) 4312be282caSSimon Glass self.out(';\n') 4322be282caSSimon Glass self.out('};\n') 4337581c01aSSimon Glass 4347581c01aSSimon Glass for alias, struct_name in self._aliases.iteritems(): 4352be282caSSimon Glass self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias, 4367581c01aSSimon Glass STRUCT_PREFIX, struct_name)) 4377581c01aSSimon Glass 4382be282caSSimon Glass def output_node(self, node): 4397581c01aSSimon Glass """Output the C code for a node 4407581c01aSSimon Glass 4417581c01aSSimon Glass Args: 4427581c01aSSimon Glass node: node to output 4437581c01aSSimon Glass """ 44456e0bbe0SSimon Glass struct_name, _ = get_compat_name(node) 4452be282caSSimon Glass var_name = conv_name_to_c(node.name) 4462be282caSSimon Glass self.buf('static struct %s%s %s%s = {\n' % 4477581c01aSSimon Glass (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) 4487581c01aSSimon Glass for pname, prop in node.props.items(): 4497581c01aSSimon Glass if pname in PROP_IGNORE_LIST or pname[0] == '#': 4507581c01aSSimon Glass continue 4512be282caSSimon Glass member_name = conv_name_to_c(prop.name) 4522be282caSSimon Glass self.buf('\t%s= ' % tab_to(3, '.' + member_name)) 4537581c01aSSimon Glass 4547581c01aSSimon Glass # Special handling for lists 4552be282caSSimon Glass if isinstance(prop.value, list): 4562be282caSSimon Glass self.buf('{') 4577581c01aSSimon Glass vals = [] 4587581c01aSSimon Glass # For phandles, output a reference to the platform data 4597581c01aSSimon Glass # of the target node. 460*cb3f9bf4SSimon Glass info = self.get_phandle_argc(prop, node.name) 461*cb3f9bf4SSimon Glass if info: 4627581c01aSSimon Glass # Process the list as pairs of (phandle, id) 4632be282caSSimon Glass value_it = iter(prop.value) 4642be282caSSimon Glass for phandle_cell, id_cell in zip(value_it, value_it): 4657581c01aSSimon Glass phandle = fdt_util.fdt32_to_cpu(phandle_cell) 4662be282caSSimon Glass id_num = fdt_util.fdt32_to_cpu(id_cell) 4670ac13c21SSimon Glass target_node = self._fdt.phandle_to_node[phandle] 4682be282caSSimon Glass name = conv_name_to_c(target_node.name) 4692be282caSSimon Glass vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num)) 4707581c01aSSimon Glass else: 4717581c01aSSimon Glass for val in prop.value: 47256e0bbe0SSimon Glass vals.append(get_value(prop.type, val)) 47312a972efSSimon Glass 47412a972efSSimon Glass # Put 8 values per line to avoid very long lines. 47512a972efSSimon Glass for i in xrange(0, len(vals), 8): 47612a972efSSimon Glass if i: 47712a972efSSimon Glass self.buf(',\n\t\t') 47812a972efSSimon Glass self.buf(', '.join(vals[i:i + 8])) 4792be282caSSimon Glass self.buf('}') 4807581c01aSSimon Glass else: 48156e0bbe0SSimon Glass self.buf(get_value(prop.type, prop.value)) 4822be282caSSimon Glass self.buf(',\n') 4832be282caSSimon Glass self.buf('};\n') 4847581c01aSSimon Glass 4857581c01aSSimon Glass # Add a device declaration 4862be282caSSimon Glass self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name) 4872be282caSSimon Glass self.buf('\t.name\t\t= "%s",\n' % struct_name) 4882be282caSSimon Glass self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) 4892be282caSSimon Glass self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name)) 4902be282caSSimon Glass self.buf('};\n') 4912be282caSSimon Glass self.buf('\n') 4927581c01aSSimon Glass 4932be282caSSimon Glass self.out(''.join(self.get_buf())) 4947581c01aSSimon Glass 4952be282caSSimon Glass def generate_tables(self): 4967581c01aSSimon Glass """Generate device defintions for the platform data 4977581c01aSSimon Glass 4987581c01aSSimon Glass This writes out C platform data initialisation data and 4997581c01aSSimon Glass U_BOOT_DEVICE() declarations for each valid node. Where a node has 5007581c01aSSimon Glass multiple compatible strings, a #define is used to make them equivalent. 5017581c01aSSimon Glass 5027581c01aSSimon Glass See the documentation in doc/driver-model/of-plat.txt for more 5037581c01aSSimon Glass information. 5047581c01aSSimon Glass """ 5052be282caSSimon Glass self.out('#include <common.h>\n') 5062be282caSSimon Glass self.out('#include <dm.h>\n') 5072be282caSSimon Glass self.out('#include <dt-structs.h>\n') 5082be282caSSimon Glass self.out('\n') 5097581c01aSSimon Glass nodes_to_output = list(self._valid_nodes) 5107581c01aSSimon Glass 5117581c01aSSimon Glass # Keep outputing nodes until there is none left 5127581c01aSSimon Glass while nodes_to_output: 5137581c01aSSimon Glass node = nodes_to_output[0] 5147581c01aSSimon Glass # Output all the node's dependencies first 5157581c01aSSimon Glass for req_node in node.phandles: 5167581c01aSSimon Glass if req_node in nodes_to_output: 5172be282caSSimon Glass self.output_node(req_node) 5187581c01aSSimon Glass nodes_to_output.remove(req_node) 5192be282caSSimon Glass self.output_node(node) 5207581c01aSSimon Glass nodes_to_output.remove(node) 521fa0ea5b0SSimon Glass 522fa0ea5b0SSimon Glass 523fa0ea5b0SSimon Glassdef run_steps(args, dtb_file, include_disabled, output): 524fa0ea5b0SSimon Glass """Run all the steps of the dtoc tool 525fa0ea5b0SSimon Glass 526fa0ea5b0SSimon Glass Args: 527fa0ea5b0SSimon Glass args: List of non-option arguments provided to the problem 528fa0ea5b0SSimon Glass dtb_file: Filename of dtb file to process 529fa0ea5b0SSimon Glass include_disabled: True to include disabled nodes 530fa0ea5b0SSimon Glass output: Name of output file 531fa0ea5b0SSimon Glass """ 532fa0ea5b0SSimon Glass if not args: 533fa0ea5b0SSimon Glass raise ValueError('Please specify a command: struct, platdata') 534fa0ea5b0SSimon Glass 535fa0ea5b0SSimon Glass plat = DtbPlatdata(dtb_file, include_disabled) 536fa0ea5b0SSimon Glass plat.scan_dtb() 537fa0ea5b0SSimon Glass plat.scan_tree() 538a28bfcc3SSimon Glass plat.scan_reg_sizes() 539fa0ea5b0SSimon Glass plat.setup_output(output) 540fa0ea5b0SSimon Glass structs = plat.scan_structs() 541fa0ea5b0SSimon Glass plat.scan_phandles() 542fa0ea5b0SSimon Glass 543fa0ea5b0SSimon Glass for cmd in args[0].split(','): 544fa0ea5b0SSimon Glass if cmd == 'struct': 545fa0ea5b0SSimon Glass plat.generate_structs(structs) 546fa0ea5b0SSimon Glass elif cmd == 'platdata': 547fa0ea5b0SSimon Glass plat.generate_tables() 548fa0ea5b0SSimon Glass else: 549fa0ea5b0SSimon Glass raise ValueError("Unknown command '%s': (use: struct, platdata)" % 550fa0ea5b0SSimon Glass cmd) 551