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 157581c01aSSimon Glassimport copy 162be282caSSimon Glassimport sys 177581c01aSSimon Glass 187581c01aSSimon Glassimport fdt 197581c01aSSimon Glassimport fdt_util 207581c01aSSimon Glass 217581c01aSSimon Glass# When we see these properties we ignore them - i.e. do not create a structure member 227581c01aSSimon GlassPROP_IGNORE_LIST = [ 237581c01aSSimon Glass '#address-cells', 247581c01aSSimon Glass '#gpio-cells', 257581c01aSSimon Glass '#size-cells', 267581c01aSSimon Glass 'compatible', 277581c01aSSimon Glass 'linux,phandle', 287581c01aSSimon Glass "status", 297581c01aSSimon Glass 'phandle', 307581c01aSSimon Glass 'u-boot,dm-pre-reloc', 317581c01aSSimon Glass 'u-boot,dm-tpl', 327581c01aSSimon Glass 'u-boot,dm-spl', 337581c01aSSimon Glass] 347581c01aSSimon Glass 357581c01aSSimon Glass# C type declarations for the tyues we support 367581c01aSSimon GlassTYPE_NAMES = { 377581c01aSSimon Glass fdt.TYPE_INT: 'fdt32_t', 387581c01aSSimon Glass fdt.TYPE_BYTE: 'unsigned char', 397581c01aSSimon Glass fdt.TYPE_STRING: 'const char *', 407581c01aSSimon Glass fdt.TYPE_BOOL: 'bool', 41ef2715f4SSimon Glass fdt.TYPE_INT64: 'fdt64_t', 422be282caSSimon Glass} 437581c01aSSimon Glass 447581c01aSSimon GlassSTRUCT_PREFIX = 'dtd_' 457581c01aSSimon GlassVAL_PREFIX = 'dtv_' 467581c01aSSimon Glass 472be282caSSimon Glassdef conv_name_to_c(name): 487581c01aSSimon Glass """Convert a device-tree name to a C identifier 497581c01aSSimon Glass 5030107b08SSimon Glass This uses multiple replace() calls instead of re.sub() since it is faster 5130107b08SSimon Glass (400ms for 1m calls versus 1000ms for the 're' version). 5230107b08SSimon Glass 537581c01aSSimon Glass Args: 547581c01aSSimon Glass name: Name to convert 557581c01aSSimon Glass Return: 567581c01aSSimon Glass String containing the C version of this name 577581c01aSSimon Glass """ 582be282caSSimon Glass new = name.replace('@', '_at_') 592be282caSSimon Glass new = new.replace('-', '_') 602be282caSSimon Glass new = new.replace(',', '_') 612be282caSSimon Glass new = new.replace('.', '_') 622be282caSSimon Glass return new 637581c01aSSimon Glass 642be282caSSimon Glassdef tab_to(num_tabs, line): 652be282caSSimon Glass """Append tabs to a line of text to reach a tab stop. 667581c01aSSimon Glass 672be282caSSimon Glass Args: 682be282caSSimon Glass num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.) 692be282caSSimon Glass line: Line of text to append to 702be282caSSimon Glass 712be282caSSimon Glass Returns: 722be282caSSimon Glass line with the correct number of tabs appeneded. If the line already 732be282caSSimon Glass extends past that tab stop then a single space is appended. 742be282caSSimon Glass """ 752be282caSSimon Glass if len(line) >= num_tabs * 8: 762be282caSSimon Glass return line + ' ' 772be282caSSimon Glass return line + '\t' * (num_tabs - len(line) // 8) 782be282caSSimon Glass 7956e0bbe0SSimon Glassdef get_value(ftype, value): 8056e0bbe0SSimon Glass """Get a value as a C expression 8156e0bbe0SSimon Glass 8256e0bbe0SSimon Glass For integers this returns a byte-swapped (little-endian) hex string 8356e0bbe0SSimon Glass For bytes this returns a hex string, e.g. 0x12 8456e0bbe0SSimon Glass For strings this returns a literal string enclosed in quotes 8556e0bbe0SSimon Glass For booleans this return 'true' 8656e0bbe0SSimon Glass 8756e0bbe0SSimon Glass Args: 8856e0bbe0SSimon Glass type: Data type (fdt_util) 8956e0bbe0SSimon Glass value: Data value, as a string of bytes 9056e0bbe0SSimon Glass """ 9156e0bbe0SSimon Glass if ftype == fdt.TYPE_INT: 9256e0bbe0SSimon Glass return '%#x' % fdt_util.fdt32_to_cpu(value) 9356e0bbe0SSimon Glass elif ftype == fdt.TYPE_BYTE: 9456e0bbe0SSimon Glass return '%#x' % ord(value[0]) 9556e0bbe0SSimon Glass elif ftype == fdt.TYPE_STRING: 9656e0bbe0SSimon Glass return '"%s"' % value 9756e0bbe0SSimon Glass elif ftype == fdt.TYPE_BOOL: 9856e0bbe0SSimon Glass return 'true' 99ef2715f4SSimon Glass elif ftype == fdt.TYPE_INT64: 100ef2715f4SSimon Glass return '%#x' % value 10156e0bbe0SSimon Glass 10256e0bbe0SSimon Glassdef get_compat_name(node): 10356e0bbe0SSimon Glass """Get a node's first compatible string as a C identifier 10456e0bbe0SSimon Glass 10556e0bbe0SSimon Glass Args: 10656e0bbe0SSimon Glass node: Node object to check 10756e0bbe0SSimon Glass Return: 10856e0bbe0SSimon Glass Tuple: 10956e0bbe0SSimon Glass C identifier for the first compatible string 11056e0bbe0SSimon Glass List of C identifiers for all the other compatible strings 11156e0bbe0SSimon Glass (possibly empty) 11256e0bbe0SSimon Glass """ 11356e0bbe0SSimon Glass compat = node.props['compatible'].value 11456e0bbe0SSimon Glass aliases = [] 11556e0bbe0SSimon Glass if isinstance(compat, list): 11656e0bbe0SSimon Glass compat, aliases = compat[0], compat[1:] 11756e0bbe0SSimon Glass return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases] 11856e0bbe0SSimon Glass 11956e0bbe0SSimon Glass 1202be282caSSimon Glassclass DtbPlatdata(object): 1217581c01aSSimon Glass """Provide a means to convert device tree binary data to platform data 1227581c01aSSimon Glass 1237581c01aSSimon Glass The output of this process is C structures which can be used in space- 1247581c01aSSimon Glass constrained encvironments where the ~3KB code overhead of device tree 1257581c01aSSimon Glass code is not affordable. 1267581c01aSSimon Glass 1277581c01aSSimon Glass Properties: 1282be282caSSimon Glass _fdt: Fdt object, referencing the device tree 1297581c01aSSimon Glass _dtb_fname: Filename of the input device tree binary file 1307581c01aSSimon Glass _valid_nodes: A list of Node object with compatible strings 131e36024b0SSimon Glass _include_disabled: true to include nodes marked status = "disabled" 1327581c01aSSimon Glass _outfile: The current output file (sys.stdout or a real file) 1337581c01aSSimon Glass _lines: Stashed list of output lines for outputting in the future 1347581c01aSSimon Glass """ 135e36024b0SSimon Glass def __init__(self, dtb_fname, include_disabled): 1362be282caSSimon Glass self._fdt = None 1377581c01aSSimon Glass self._dtb_fname = dtb_fname 1387581c01aSSimon Glass self._valid_nodes = None 139e36024b0SSimon Glass self._include_disabled = include_disabled 1407581c01aSSimon Glass self._outfile = None 1417581c01aSSimon Glass self._lines = [] 1427581c01aSSimon Glass self._aliases = {} 1437581c01aSSimon Glass 1442be282caSSimon Glass def setup_output(self, fname): 1457581c01aSSimon Glass """Set up the output destination 1467581c01aSSimon Glass 1472be282caSSimon Glass Once this is done, future calls to self.out() will output to this 1487581c01aSSimon Glass file. 1497581c01aSSimon Glass 1507581c01aSSimon Glass Args: 1517581c01aSSimon Glass fname: Filename to send output to, or '-' for stdout 1527581c01aSSimon Glass """ 1537581c01aSSimon Glass if fname == '-': 1547581c01aSSimon Glass self._outfile = sys.stdout 1557581c01aSSimon Glass else: 1567581c01aSSimon Glass self._outfile = open(fname, 'w') 1577581c01aSSimon Glass 1582be282caSSimon Glass def out(self, line): 1597581c01aSSimon Glass """Output a string to the output file 1607581c01aSSimon Glass 1617581c01aSSimon Glass Args: 1622be282caSSimon Glass line: String to output 1637581c01aSSimon Glass """ 1642be282caSSimon Glass self._outfile.write(line) 1657581c01aSSimon Glass 1662be282caSSimon Glass def buf(self, line): 1677581c01aSSimon Glass """Buffer up a string to send later 1687581c01aSSimon Glass 1697581c01aSSimon Glass Args: 1702be282caSSimon Glass line: String to add to our 'buffer' list 1717581c01aSSimon Glass """ 1722be282caSSimon Glass self._lines.append(line) 1737581c01aSSimon Glass 1742be282caSSimon Glass def get_buf(self): 1757581c01aSSimon Glass """Get the contents of the output buffer, and clear it 1767581c01aSSimon Glass 1777581c01aSSimon Glass Returns: 1787581c01aSSimon Glass The output buffer, which is then cleared for future use 1797581c01aSSimon Glass """ 1807581c01aSSimon Glass lines = self._lines 1817581c01aSSimon Glass self._lines = [] 1827581c01aSSimon Glass return lines 1837581c01aSSimon Glass 184*7088d44bSSimon Glass def is_phandle(self, prop): 185*7088d44bSSimon Glass """Check if a node contains phandles 186*7088d44bSSimon Glass 187*7088d44bSSimon Glass We have no reliable way of detecting whether a node uses a phandle 188*7088d44bSSimon Glass or not. As an interim measure, use a list of known property names. 189*7088d44bSSimon Glass 190*7088d44bSSimon Glass Args: 191*7088d44bSSimon Glass prop: Prop object to check 192*7088d44bSSimon Glass Return: 193*7088d44bSSimon Glass True if the object value contains phandles, else False 194*7088d44bSSimon Glass """ 195*7088d44bSSimon Glass if prop.name in ['clocks']: 196*7088d44bSSimon Glass return True 197*7088d44bSSimon Glass return False 198*7088d44bSSimon Glass 1992be282caSSimon Glass def scan_dtb(self): 200f1a7ba1dSAnatolij Gustschin """Scan the device tree to obtain a tree of nodes and properties 2017581c01aSSimon Glass 2022be282caSSimon Glass Once this is done, self._fdt.GetRoot() can be called to obtain the 2037581c01aSSimon Glass device tree root node, and progress from there. 2047581c01aSSimon Glass """ 2052be282caSSimon Glass self._fdt = fdt.FdtScan(self._dtb_fname) 2067581c01aSSimon Glass 2072be282caSSimon Glass def scan_node(self, root): 2082be282caSSimon Glass """Scan a node and subnodes to build a tree of node and phandle info 2092be282caSSimon Glass 2100ac13c21SSimon Glass This adds each node to self._valid_nodes. 2112be282caSSimon Glass 2122be282caSSimon Glass Args: 2132be282caSSimon Glass root: Root node for scan 2142be282caSSimon Glass """ 2157581c01aSSimon Glass for node in root.subnodes: 2167581c01aSSimon Glass if 'compatible' in node.props: 2177581c01aSSimon Glass status = node.props.get('status') 218e36024b0SSimon Glass if (not self._include_disabled and not status or 2197581c01aSSimon Glass status.value != 'disabled'): 2207581c01aSSimon Glass self._valid_nodes.append(node) 2217581c01aSSimon Glass 2227581c01aSSimon Glass # recurse to handle any subnodes 2232be282caSSimon Glass self.scan_node(node) 2247581c01aSSimon Glass 2252be282caSSimon Glass def scan_tree(self): 2267581c01aSSimon Glass """Scan the device tree for useful information 2277581c01aSSimon Glass 2287581c01aSSimon Glass This fills in the following properties: 2297581c01aSSimon Glass _valid_nodes: A list of nodes we wish to consider include in the 2307581c01aSSimon Glass platform data 2317581c01aSSimon Glass """ 2327581c01aSSimon Glass self._valid_nodes = [] 2332be282caSSimon Glass return self.scan_node(self._fdt.GetRoot()) 2347581c01aSSimon Glass 235a28bfcc3SSimon Glass @staticmethod 236a28bfcc3SSimon Glass def get_num_cells(node): 237a28bfcc3SSimon Glass """Get the number of cells in addresses and sizes for this node 238a28bfcc3SSimon Glass 239a28bfcc3SSimon Glass Args: 240a28bfcc3SSimon Glass node: Node to check 241a28bfcc3SSimon Glass 242a28bfcc3SSimon Glass Returns: 243a28bfcc3SSimon Glass Tuple: 244a28bfcc3SSimon Glass Number of address cells for this node 245a28bfcc3SSimon Glass Number of size cells for this node 246a28bfcc3SSimon Glass """ 247a28bfcc3SSimon Glass parent = node.parent 248a28bfcc3SSimon Glass na, ns = 2, 2 249a28bfcc3SSimon Glass if parent: 250a28bfcc3SSimon Glass na_prop = parent.props.get('#address-cells') 251a28bfcc3SSimon Glass ns_prop = parent.props.get('#size-cells') 252a28bfcc3SSimon Glass if na_prop: 253a28bfcc3SSimon Glass na = fdt_util.fdt32_to_cpu(na_prop.value) 254a28bfcc3SSimon Glass if ns_prop: 255a28bfcc3SSimon Glass ns = fdt_util.fdt32_to_cpu(ns_prop.value) 256a28bfcc3SSimon Glass return na, ns 257a28bfcc3SSimon Glass 258a28bfcc3SSimon Glass def scan_reg_sizes(self): 259a28bfcc3SSimon Glass """Scan for 64-bit 'reg' properties and update the values 260a28bfcc3SSimon Glass 261a28bfcc3SSimon Glass This finds 'reg' properties with 64-bit data and converts the value to 262a28bfcc3SSimon Glass an array of 64-values. This allows it to be output in a way that the 263a28bfcc3SSimon Glass C code can read. 264a28bfcc3SSimon Glass """ 265a28bfcc3SSimon Glass for node in self._valid_nodes: 266a28bfcc3SSimon Glass reg = node.props.get('reg') 267a28bfcc3SSimon Glass if not reg: 268a28bfcc3SSimon Glass continue 269a28bfcc3SSimon Glass na, ns = self.get_num_cells(node) 270a28bfcc3SSimon Glass total = na + ns 271a28bfcc3SSimon Glass 272a28bfcc3SSimon Glass if reg.type != fdt.TYPE_INT: 273a28bfcc3SSimon Glass raise ValueError("Node '%s' reg property is not an int") 274a28bfcc3SSimon Glass if len(reg.value) % total: 275a28bfcc3SSimon Glass raise ValueError("Node '%s' reg property has %d cells " 276a28bfcc3SSimon Glass 'which is not a multiple of na + ns = %d + %d)' % 277a28bfcc3SSimon Glass (node.name, len(reg.value), na, ns)) 278a28bfcc3SSimon Glass reg.na = na 279a28bfcc3SSimon Glass reg.ns = ns 280a28bfcc3SSimon Glass if na != 1 or ns != 1: 281a28bfcc3SSimon Glass reg.type = fdt.TYPE_INT64 282a28bfcc3SSimon Glass i = 0 283a28bfcc3SSimon Glass new_value = [] 284a28bfcc3SSimon Glass val = reg.value 285a28bfcc3SSimon Glass if not isinstance(val, list): 286a28bfcc3SSimon Glass val = [val] 287a28bfcc3SSimon Glass while i < len(val): 288a28bfcc3SSimon Glass addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na) 289a28bfcc3SSimon Glass i += na 290a28bfcc3SSimon Glass size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns) 291a28bfcc3SSimon Glass i += ns 292a28bfcc3SSimon Glass new_value += [addr, size] 293a28bfcc3SSimon Glass reg.value = new_value 294a28bfcc3SSimon Glass 2952be282caSSimon Glass def scan_structs(self): 2967581c01aSSimon Glass """Scan the device tree building up the C structures we will use. 2977581c01aSSimon Glass 2987581c01aSSimon Glass Build a dict keyed by C struct name containing a dict of Prop 2997581c01aSSimon Glass object for each struct field (keyed by property name). Where the 3007581c01aSSimon Glass same struct appears multiple times, try to use the 'widest' 3017581c01aSSimon Glass property, i.e. the one with a type which can express all others. 3027581c01aSSimon Glass 3037581c01aSSimon Glass Once the widest property is determined, all other properties are 3047581c01aSSimon Glass updated to match that width. 3057581c01aSSimon Glass """ 3067581c01aSSimon Glass structs = {} 3077581c01aSSimon Glass for node in self._valid_nodes: 30856e0bbe0SSimon Glass node_name, _ = get_compat_name(node) 3097581c01aSSimon Glass fields = {} 3107581c01aSSimon Glass 3117581c01aSSimon Glass # Get a list of all the valid properties in this node. 3127581c01aSSimon Glass for name, prop in node.props.items(): 3137581c01aSSimon Glass if name not in PROP_IGNORE_LIST and name[0] != '#': 3147581c01aSSimon Glass fields[name] = copy.deepcopy(prop) 3157581c01aSSimon Glass 3167581c01aSSimon Glass # If we've seen this node_name before, update the existing struct. 3177581c01aSSimon Glass if node_name in structs: 3187581c01aSSimon Glass struct = structs[node_name] 3197581c01aSSimon Glass for name, prop in fields.items(): 3207581c01aSSimon Glass oldprop = struct.get(name) 3217581c01aSSimon Glass if oldprop: 3227581c01aSSimon Glass oldprop.Widen(prop) 3237581c01aSSimon Glass else: 3247581c01aSSimon Glass struct[name] = prop 3257581c01aSSimon Glass 3267581c01aSSimon Glass # Otherwise store this as a new struct. 3277581c01aSSimon Glass else: 3287581c01aSSimon Glass structs[node_name] = fields 3297581c01aSSimon Glass 3307581c01aSSimon Glass upto = 0 3317581c01aSSimon Glass for node in self._valid_nodes: 33256e0bbe0SSimon Glass node_name, _ = get_compat_name(node) 3337581c01aSSimon Glass struct = structs[node_name] 3347581c01aSSimon Glass for name, prop in node.props.items(): 3357581c01aSSimon Glass if name not in PROP_IGNORE_LIST and name[0] != '#': 3367581c01aSSimon Glass prop.Widen(struct[name]) 3377581c01aSSimon Glass upto += 1 3387581c01aSSimon Glass 33956e0bbe0SSimon Glass struct_name, aliases = get_compat_name(node) 3407581c01aSSimon Glass for alias in aliases: 3417581c01aSSimon Glass self._aliases[alias] = struct_name 3427581c01aSSimon Glass 3437581c01aSSimon Glass return structs 3447581c01aSSimon Glass 3452be282caSSimon Glass def scan_phandles(self): 3467581c01aSSimon Glass """Figure out what phandles each node uses 3477581c01aSSimon Glass 3487581c01aSSimon Glass We need to be careful when outputing nodes that use phandles since 3497581c01aSSimon Glass they must come after the declaration of the phandles in the C file. 3507581c01aSSimon Glass Otherwise we get a compiler error since the phandle struct is not yet 3517581c01aSSimon Glass declared. 3527581c01aSSimon Glass 3537581c01aSSimon Glass This function adds to each node a list of phandle nodes that the node 3547581c01aSSimon Glass depends on. This allows us to output things in the right order. 3557581c01aSSimon Glass """ 3567581c01aSSimon Glass for node in self._valid_nodes: 3577581c01aSSimon Glass node.phandles = set() 3587581c01aSSimon Glass for pname, prop in node.props.items(): 3597581c01aSSimon Glass if pname in PROP_IGNORE_LIST or pname[0] == '#': 3607581c01aSSimon Glass continue 3612be282caSSimon Glass if isinstance(prop.value, list): 362*7088d44bSSimon Glass if self.is_phandle(prop): 3637581c01aSSimon Glass # Process the list as pairs of (phandle, id) 3642be282caSSimon Glass value_it = iter(prop.value) 3652be282caSSimon Glass for phandle_cell, _ in zip(value_it, value_it): 3667581c01aSSimon Glass phandle = fdt_util.fdt32_to_cpu(phandle_cell) 3670ac13c21SSimon Glass target_node = self._fdt.phandle_to_node[phandle] 3687581c01aSSimon Glass node.phandles.add(target_node) 3697581c01aSSimon Glass 3707581c01aSSimon Glass 3712be282caSSimon Glass def generate_structs(self, structs): 3727581c01aSSimon Glass """Generate struct defintions for the platform data 3737581c01aSSimon Glass 3747581c01aSSimon Glass This writes out the body of a header file consisting of structure 3757581c01aSSimon Glass definitions for node in self._valid_nodes. See the documentation in 3767581c01aSSimon Glass README.of-plat for more information. 3777581c01aSSimon Glass """ 3782be282caSSimon Glass self.out('#include <stdbool.h>\n') 3792be282caSSimon Glass self.out('#include <libfdt.h>\n') 3807581c01aSSimon Glass 3817581c01aSSimon Glass # Output the struct definition 3827581c01aSSimon Glass for name in sorted(structs): 3832be282caSSimon Glass self.out('struct %s%s {\n' % (STRUCT_PREFIX, name)) 3847581c01aSSimon Glass for pname in sorted(structs[name]): 3857581c01aSSimon Glass prop = structs[name][pname] 386*7088d44bSSimon Glass if self.is_phandle(prop): 3877581c01aSSimon Glass # For phandles, include a reference to the target 3882be282caSSimon Glass self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'), 3892be282caSSimon Glass conv_name_to_c(prop.name), 3907581c01aSSimon Glass len(prop.value) / 2)) 3917581c01aSSimon Glass else: 3927581c01aSSimon Glass ptype = TYPE_NAMES[prop.type] 3932be282caSSimon Glass self.out('\t%s%s' % (tab_to(2, ptype), 3942be282caSSimon Glass conv_name_to_c(prop.name))) 3952be282caSSimon Glass if isinstance(prop.value, list): 3962be282caSSimon Glass self.out('[%d]' % len(prop.value)) 3972be282caSSimon Glass self.out(';\n') 3982be282caSSimon Glass self.out('};\n') 3997581c01aSSimon Glass 4007581c01aSSimon Glass for alias, struct_name in self._aliases.iteritems(): 4012be282caSSimon Glass self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias, 4027581c01aSSimon Glass STRUCT_PREFIX, struct_name)) 4037581c01aSSimon Glass 4042be282caSSimon Glass def output_node(self, node): 4057581c01aSSimon Glass """Output the C code for a node 4067581c01aSSimon Glass 4077581c01aSSimon Glass Args: 4087581c01aSSimon Glass node: node to output 4097581c01aSSimon Glass """ 41056e0bbe0SSimon Glass struct_name, _ = get_compat_name(node) 4112be282caSSimon Glass var_name = conv_name_to_c(node.name) 4122be282caSSimon Glass self.buf('static struct %s%s %s%s = {\n' % 4137581c01aSSimon Glass (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) 4147581c01aSSimon Glass for pname, prop in node.props.items(): 4157581c01aSSimon Glass if pname in PROP_IGNORE_LIST or pname[0] == '#': 4167581c01aSSimon Glass continue 4172be282caSSimon Glass member_name = conv_name_to_c(prop.name) 4182be282caSSimon Glass self.buf('\t%s= ' % tab_to(3, '.' + member_name)) 4197581c01aSSimon Glass 4207581c01aSSimon Glass # Special handling for lists 4212be282caSSimon Glass if isinstance(prop.value, list): 4222be282caSSimon Glass self.buf('{') 4237581c01aSSimon Glass vals = [] 4247581c01aSSimon Glass # For phandles, output a reference to the platform data 4257581c01aSSimon Glass # of the target node. 426*7088d44bSSimon Glass if self.is_phandle(prop): 4277581c01aSSimon Glass # Process the list as pairs of (phandle, id) 4282be282caSSimon Glass value_it = iter(prop.value) 4292be282caSSimon Glass for phandle_cell, id_cell in zip(value_it, value_it): 4307581c01aSSimon Glass phandle = fdt_util.fdt32_to_cpu(phandle_cell) 4312be282caSSimon Glass id_num = fdt_util.fdt32_to_cpu(id_cell) 4320ac13c21SSimon Glass target_node = self._fdt.phandle_to_node[phandle] 4332be282caSSimon Glass name = conv_name_to_c(target_node.name) 4342be282caSSimon Glass vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num)) 4357581c01aSSimon Glass else: 4367581c01aSSimon Glass for val in prop.value: 43756e0bbe0SSimon Glass vals.append(get_value(prop.type, val)) 43812a972efSSimon Glass 43912a972efSSimon Glass # Put 8 values per line to avoid very long lines. 44012a972efSSimon Glass for i in xrange(0, len(vals), 8): 44112a972efSSimon Glass if i: 44212a972efSSimon Glass self.buf(',\n\t\t') 44312a972efSSimon Glass self.buf(', '.join(vals[i:i + 8])) 4442be282caSSimon Glass self.buf('}') 4457581c01aSSimon Glass else: 44656e0bbe0SSimon Glass self.buf(get_value(prop.type, prop.value)) 4472be282caSSimon Glass self.buf(',\n') 4482be282caSSimon Glass self.buf('};\n') 4497581c01aSSimon Glass 4507581c01aSSimon Glass # Add a device declaration 4512be282caSSimon Glass self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name) 4522be282caSSimon Glass self.buf('\t.name\t\t= "%s",\n' % struct_name) 4532be282caSSimon Glass self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) 4542be282caSSimon Glass self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name)) 4552be282caSSimon Glass self.buf('};\n') 4562be282caSSimon Glass self.buf('\n') 4577581c01aSSimon Glass 4582be282caSSimon Glass self.out(''.join(self.get_buf())) 4597581c01aSSimon Glass 4602be282caSSimon Glass def generate_tables(self): 4617581c01aSSimon Glass """Generate device defintions for the platform data 4627581c01aSSimon Glass 4637581c01aSSimon Glass This writes out C platform data initialisation data and 4647581c01aSSimon Glass U_BOOT_DEVICE() declarations for each valid node. Where a node has 4657581c01aSSimon Glass multiple compatible strings, a #define is used to make them equivalent. 4667581c01aSSimon Glass 4677581c01aSSimon Glass See the documentation in doc/driver-model/of-plat.txt for more 4687581c01aSSimon Glass information. 4697581c01aSSimon Glass """ 4702be282caSSimon Glass self.out('#include <common.h>\n') 4712be282caSSimon Glass self.out('#include <dm.h>\n') 4722be282caSSimon Glass self.out('#include <dt-structs.h>\n') 4732be282caSSimon Glass self.out('\n') 4747581c01aSSimon Glass nodes_to_output = list(self._valid_nodes) 4757581c01aSSimon Glass 4767581c01aSSimon Glass # Keep outputing nodes until there is none left 4777581c01aSSimon Glass while nodes_to_output: 4787581c01aSSimon Glass node = nodes_to_output[0] 4797581c01aSSimon Glass # Output all the node's dependencies first 4807581c01aSSimon Glass for req_node in node.phandles: 4817581c01aSSimon Glass if req_node in nodes_to_output: 4822be282caSSimon Glass self.output_node(req_node) 4837581c01aSSimon Glass nodes_to_output.remove(req_node) 4842be282caSSimon Glass self.output_node(node) 4857581c01aSSimon Glass nodes_to_output.remove(node) 486fa0ea5b0SSimon Glass 487fa0ea5b0SSimon Glass 488fa0ea5b0SSimon Glassdef run_steps(args, dtb_file, include_disabled, output): 489fa0ea5b0SSimon Glass """Run all the steps of the dtoc tool 490fa0ea5b0SSimon Glass 491fa0ea5b0SSimon Glass Args: 492fa0ea5b0SSimon Glass args: List of non-option arguments provided to the problem 493fa0ea5b0SSimon Glass dtb_file: Filename of dtb file to process 494fa0ea5b0SSimon Glass include_disabled: True to include disabled nodes 495fa0ea5b0SSimon Glass output: Name of output file 496fa0ea5b0SSimon Glass """ 497fa0ea5b0SSimon Glass if not args: 498fa0ea5b0SSimon Glass raise ValueError('Please specify a command: struct, platdata') 499fa0ea5b0SSimon Glass 500fa0ea5b0SSimon Glass plat = DtbPlatdata(dtb_file, include_disabled) 501fa0ea5b0SSimon Glass plat.scan_dtb() 502fa0ea5b0SSimon Glass plat.scan_tree() 503a28bfcc3SSimon Glass plat.scan_reg_sizes() 504fa0ea5b0SSimon Glass plat.setup_output(output) 505fa0ea5b0SSimon Glass structs = plat.scan_structs() 506fa0ea5b0SSimon Glass plat.scan_phandles() 507fa0ea5b0SSimon Glass 508fa0ea5b0SSimon Glass for cmd in args[0].split(','): 509fa0ea5b0SSimon Glass if cmd == 'struct': 510fa0ea5b0SSimon Glass plat.generate_structs(structs) 511fa0ea5b0SSimon Glass elif cmd == 'platdata': 512fa0ea5b0SSimon Glass plat.generate_tables() 513fa0ea5b0SSimon Glass else: 514fa0ea5b0SSimon Glass raise ValueError("Unknown command '%s': (use: struct, platdata)" % 515fa0ea5b0SSimon Glass cmd) 516