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 9*2be282caSSimon Glass"""Device tree to platform data class 10*2be282caSSimon Glass 11*2be282caSSimon GlassThis supports converting device tree data to C structures definitions and 12*2be282caSSimon Glassstatic data. 13*2be282caSSimon Glass""" 14*2be282caSSimon Glass 157581c01aSSimon Glassimport copy 16*2be282caSSimon 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', 41*2be282caSSimon Glass} 427581c01aSSimon Glass 437581c01aSSimon GlassSTRUCT_PREFIX = 'dtd_' 447581c01aSSimon GlassVAL_PREFIX = 'dtv_' 457581c01aSSimon Glass 46*2be282caSSimon Glassdef conv_name_to_c(name): 477581c01aSSimon Glass """Convert a device-tree name to a C identifier 487581c01aSSimon Glass 497581c01aSSimon Glass Args: 507581c01aSSimon Glass name: Name to convert 517581c01aSSimon Glass Return: 527581c01aSSimon Glass String containing the C version of this name 537581c01aSSimon Glass """ 54*2be282caSSimon Glass new = name.replace('@', '_at_') 55*2be282caSSimon Glass new = new.replace('-', '_') 56*2be282caSSimon Glass new = new.replace(',', '_') 57*2be282caSSimon Glass new = new.replace('.', '_') 58*2be282caSSimon Glass new = new.replace('/', '__') 59*2be282caSSimon Glass return new 607581c01aSSimon Glass 61*2be282caSSimon Glassdef tab_to(num_tabs, line): 62*2be282caSSimon Glass """Append tabs to a line of text to reach a tab stop. 637581c01aSSimon Glass 64*2be282caSSimon Glass Args: 65*2be282caSSimon Glass num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.) 66*2be282caSSimon Glass line: Line of text to append to 67*2be282caSSimon Glass 68*2be282caSSimon Glass Returns: 69*2be282caSSimon Glass line with the correct number of tabs appeneded. If the line already 70*2be282caSSimon Glass extends past that tab stop then a single space is appended. 71*2be282caSSimon Glass """ 72*2be282caSSimon Glass if len(line) >= num_tabs * 8: 73*2be282caSSimon Glass return line + ' ' 74*2be282caSSimon Glass return line + '\t' * (num_tabs - len(line) // 8) 75*2be282caSSimon Glass 76*2be282caSSimon Glassclass DtbPlatdata(object): 777581c01aSSimon Glass """Provide a means to convert device tree binary data to platform data 787581c01aSSimon Glass 797581c01aSSimon Glass The output of this process is C structures which can be used in space- 807581c01aSSimon Glass constrained encvironments where the ~3KB code overhead of device tree 817581c01aSSimon Glass code is not affordable. 827581c01aSSimon Glass 837581c01aSSimon Glass Properties: 84*2be282caSSimon Glass _fdt: Fdt object, referencing the device tree 857581c01aSSimon Glass _dtb_fname: Filename of the input device tree binary file 867581c01aSSimon Glass _valid_nodes: A list of Node object with compatible strings 877581c01aSSimon Glass _options: Command-line options 88*2be282caSSimon Glass _phandle_nodes: A dict of nodes indexed by phandle number (1, 2...) 897581c01aSSimon Glass _outfile: The current output file (sys.stdout or a real file) 907581c01aSSimon Glass _lines: Stashed list of output lines for outputting in the future 91*2be282caSSimon Glass _phandle_nodes: A dict of Nodes indexed by phandle (an integer) 927581c01aSSimon Glass """ 937581c01aSSimon Glass def __init__(self, dtb_fname, options): 94*2be282caSSimon Glass self._fdt = None 957581c01aSSimon Glass self._dtb_fname = dtb_fname 967581c01aSSimon Glass self._valid_nodes = None 977581c01aSSimon Glass self._options = options 98*2be282caSSimon Glass self._phandle_nodes = {} 997581c01aSSimon Glass self._outfile = None 1007581c01aSSimon Glass self._lines = [] 1017581c01aSSimon Glass self._aliases = {} 1027581c01aSSimon Glass 103*2be282caSSimon Glass def setup_output(self, fname): 1047581c01aSSimon Glass """Set up the output destination 1057581c01aSSimon Glass 106*2be282caSSimon Glass Once this is done, future calls to self.out() will output to this 1077581c01aSSimon Glass file. 1087581c01aSSimon Glass 1097581c01aSSimon Glass Args: 1107581c01aSSimon Glass fname: Filename to send output to, or '-' for stdout 1117581c01aSSimon Glass """ 1127581c01aSSimon Glass if fname == '-': 1137581c01aSSimon Glass self._outfile = sys.stdout 1147581c01aSSimon Glass else: 1157581c01aSSimon Glass self._outfile = open(fname, 'w') 1167581c01aSSimon Glass 117*2be282caSSimon Glass def out(self, line): 1187581c01aSSimon Glass """Output a string to the output file 1197581c01aSSimon Glass 1207581c01aSSimon Glass Args: 121*2be282caSSimon Glass line: String to output 1227581c01aSSimon Glass """ 123*2be282caSSimon Glass self._outfile.write(line) 1247581c01aSSimon Glass 125*2be282caSSimon Glass def buf(self, line): 1267581c01aSSimon Glass """Buffer up a string to send later 1277581c01aSSimon Glass 1287581c01aSSimon Glass Args: 129*2be282caSSimon Glass line: String to add to our 'buffer' list 1307581c01aSSimon Glass """ 131*2be282caSSimon Glass self._lines.append(line) 1327581c01aSSimon Glass 133*2be282caSSimon Glass def get_buf(self): 1347581c01aSSimon Glass """Get the contents of the output buffer, and clear it 1357581c01aSSimon Glass 1367581c01aSSimon Glass Returns: 1377581c01aSSimon Glass The output buffer, which is then cleared for future use 1387581c01aSSimon Glass """ 1397581c01aSSimon Glass lines = self._lines 1407581c01aSSimon Glass self._lines = [] 1417581c01aSSimon Glass return lines 1427581c01aSSimon Glass 143*2be282caSSimon Glass @staticmethod 144*2be282caSSimon Glass def get_value(ftype, value): 1457581c01aSSimon Glass """Get a value as a C expression 1467581c01aSSimon Glass 1477581c01aSSimon Glass For integers this returns a byte-swapped (little-endian) hex string 1487581c01aSSimon Glass For bytes this returns a hex string, e.g. 0x12 1497581c01aSSimon Glass For strings this returns a literal string enclosed in quotes 1507581c01aSSimon Glass For booleans this return 'true' 1517581c01aSSimon Glass 1527581c01aSSimon Glass Args: 1537581c01aSSimon Glass type: Data type (fdt_util) 1547581c01aSSimon Glass value: Data value, as a string of bytes 1557581c01aSSimon Glass """ 156*2be282caSSimon Glass if ftype == fdt.TYPE_INT: 1577581c01aSSimon Glass return '%#x' % fdt_util.fdt32_to_cpu(value) 158*2be282caSSimon Glass elif ftype == fdt.TYPE_BYTE: 1597581c01aSSimon Glass return '%#x' % ord(value[0]) 160*2be282caSSimon Glass elif ftype == fdt.TYPE_STRING: 1617581c01aSSimon Glass return '"%s"' % value 162*2be282caSSimon Glass elif ftype == fdt.TYPE_BOOL: 1637581c01aSSimon Glass return 'true' 1647581c01aSSimon Glass 165*2be282caSSimon Glass @staticmethod 166*2be282caSSimon Glass def get_compat_name(node): 1677581c01aSSimon Glass """Get a node's first compatible string as a C identifier 1687581c01aSSimon Glass 1697581c01aSSimon Glass Args: 1707581c01aSSimon Glass node: Node object to check 1717581c01aSSimon Glass Return: 1727581c01aSSimon Glass C identifier for the first compatible string 1737581c01aSSimon Glass """ 1747581c01aSSimon Glass compat = node.props['compatible'].value 1757581c01aSSimon Glass aliases = [] 176*2be282caSSimon Glass if isinstance(compat, list): 1777581c01aSSimon Glass compat, aliases = compat[0], compat[1:] 178*2be282caSSimon Glass return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases] 1797581c01aSSimon Glass 180*2be282caSSimon Glass def scan_dtb(self): 1817581c01aSSimon Glass """Scan the device tree to obtain a tree of notes and properties 1827581c01aSSimon Glass 183*2be282caSSimon Glass Once this is done, self._fdt.GetRoot() can be called to obtain the 1847581c01aSSimon Glass device tree root node, and progress from there. 1857581c01aSSimon Glass """ 186*2be282caSSimon Glass self._fdt = fdt.FdtScan(self._dtb_fname) 1877581c01aSSimon Glass 188*2be282caSSimon Glass def scan_node(self, root): 189*2be282caSSimon Glass """Scan a node and subnodes to build a tree of node and phandle info 190*2be282caSSimon Glass 191*2be282caSSimon Glass This adds each node to self._valid_nodes and each phandle to 192*2be282caSSimon Glass self._phandle_nodes. 193*2be282caSSimon Glass 194*2be282caSSimon Glass Args: 195*2be282caSSimon Glass root: Root node for scan 196*2be282caSSimon Glass """ 1977581c01aSSimon Glass for node in root.subnodes: 1987581c01aSSimon Glass if 'compatible' in node.props: 1997581c01aSSimon Glass status = node.props.get('status') 2007581c01aSSimon Glass if (not self._options.include_disabled and not status or 2017581c01aSSimon Glass status.value != 'disabled'): 2027581c01aSSimon Glass self._valid_nodes.append(node) 2037581c01aSSimon Glass phandle_prop = node.props.get('phandle') 2047581c01aSSimon Glass if phandle_prop: 2057581c01aSSimon Glass phandle = phandle_prop.GetPhandle() 206*2be282caSSimon Glass self._phandle_nodes[phandle] = node 2077581c01aSSimon Glass 2087581c01aSSimon Glass # recurse to handle any subnodes 209*2be282caSSimon Glass self.scan_node(node) 2107581c01aSSimon Glass 211*2be282caSSimon Glass def scan_tree(self): 2127581c01aSSimon Glass """Scan the device tree for useful information 2137581c01aSSimon Glass 2147581c01aSSimon Glass This fills in the following properties: 215*2be282caSSimon Glass _phandle_nodes: A dict of Nodes indexed by phandle (an integer) 2167581c01aSSimon Glass _valid_nodes: A list of nodes we wish to consider include in the 2177581c01aSSimon Glass platform data 2187581c01aSSimon Glass """ 219*2be282caSSimon Glass self._phandle_nodes = {} 2207581c01aSSimon Glass self._valid_nodes = [] 221*2be282caSSimon Glass return self.scan_node(self._fdt.GetRoot()) 2227581c01aSSimon Glass 223*2be282caSSimon Glass @staticmethod 224*2be282caSSimon Glass def is_phandle(prop): 2257581c01aSSimon Glass """Check if a node contains phandles 2267581c01aSSimon Glass 2277581c01aSSimon Glass We have no reliable way of detecting whether a node uses a phandle 2287581c01aSSimon Glass or not. As an interim measure, use a list of known property names. 2297581c01aSSimon Glass 2307581c01aSSimon Glass Args: 2317581c01aSSimon Glass prop: Prop object to check 2327581c01aSSimon Glass Return: 2337581c01aSSimon Glass True if the object value contains phandles, else False 2347581c01aSSimon Glass """ 2357581c01aSSimon Glass if prop.name in ['clocks']: 2367581c01aSSimon Glass return True 2377581c01aSSimon Glass return False 2387581c01aSSimon Glass 239*2be282caSSimon Glass def scan_structs(self): 2407581c01aSSimon Glass """Scan the device tree building up the C structures we will use. 2417581c01aSSimon Glass 2427581c01aSSimon Glass Build a dict keyed by C struct name containing a dict of Prop 2437581c01aSSimon Glass object for each struct field (keyed by property name). Where the 2447581c01aSSimon Glass same struct appears multiple times, try to use the 'widest' 2457581c01aSSimon Glass property, i.e. the one with a type which can express all others. 2467581c01aSSimon Glass 2477581c01aSSimon Glass Once the widest property is determined, all other properties are 2487581c01aSSimon Glass updated to match that width. 2497581c01aSSimon Glass """ 2507581c01aSSimon Glass structs = {} 2517581c01aSSimon Glass for node in self._valid_nodes: 252*2be282caSSimon Glass node_name, _ = self.get_compat_name(node) 2537581c01aSSimon Glass fields = {} 2547581c01aSSimon Glass 2557581c01aSSimon Glass # Get a list of all the valid properties in this node. 2567581c01aSSimon Glass for name, prop in node.props.items(): 2577581c01aSSimon Glass if name not in PROP_IGNORE_LIST and name[0] != '#': 2587581c01aSSimon Glass fields[name] = copy.deepcopy(prop) 2597581c01aSSimon Glass 2607581c01aSSimon Glass # If we've seen this node_name before, update the existing struct. 2617581c01aSSimon Glass if node_name in structs: 2627581c01aSSimon Glass struct = structs[node_name] 2637581c01aSSimon Glass for name, prop in fields.items(): 2647581c01aSSimon Glass oldprop = struct.get(name) 2657581c01aSSimon Glass if oldprop: 2667581c01aSSimon Glass oldprop.Widen(prop) 2677581c01aSSimon Glass else: 2687581c01aSSimon Glass struct[name] = prop 2697581c01aSSimon Glass 2707581c01aSSimon Glass # Otherwise store this as a new struct. 2717581c01aSSimon Glass else: 2727581c01aSSimon Glass structs[node_name] = fields 2737581c01aSSimon Glass 2747581c01aSSimon Glass upto = 0 2757581c01aSSimon Glass for node in self._valid_nodes: 276*2be282caSSimon Glass node_name, _ = self.get_compat_name(node) 2777581c01aSSimon Glass struct = structs[node_name] 2787581c01aSSimon Glass for name, prop in node.props.items(): 2797581c01aSSimon Glass if name not in PROP_IGNORE_LIST and name[0] != '#': 2807581c01aSSimon Glass prop.Widen(struct[name]) 2817581c01aSSimon Glass upto += 1 2827581c01aSSimon Glass 283*2be282caSSimon Glass struct_name, aliases = self.get_compat_name(node) 2847581c01aSSimon Glass for alias in aliases: 2857581c01aSSimon Glass self._aliases[alias] = struct_name 2867581c01aSSimon Glass 2877581c01aSSimon Glass return structs 2887581c01aSSimon Glass 289*2be282caSSimon Glass def scan_phandles(self): 2907581c01aSSimon Glass """Figure out what phandles each node uses 2917581c01aSSimon Glass 2927581c01aSSimon Glass We need to be careful when outputing nodes that use phandles since 2937581c01aSSimon Glass they must come after the declaration of the phandles in the C file. 2947581c01aSSimon Glass Otherwise we get a compiler error since the phandle struct is not yet 2957581c01aSSimon Glass declared. 2967581c01aSSimon Glass 2977581c01aSSimon Glass This function adds to each node a list of phandle nodes that the node 2987581c01aSSimon Glass depends on. This allows us to output things in the right order. 2997581c01aSSimon Glass """ 3007581c01aSSimon Glass for node in self._valid_nodes: 3017581c01aSSimon Glass node.phandles = set() 3027581c01aSSimon Glass for pname, prop in node.props.items(): 3037581c01aSSimon Glass if pname in PROP_IGNORE_LIST or pname[0] == '#': 3047581c01aSSimon Glass continue 305*2be282caSSimon Glass if isinstance(prop.value, list): 306*2be282caSSimon Glass if self.is_phandle(prop): 3077581c01aSSimon Glass # Process the list as pairs of (phandle, id) 308*2be282caSSimon Glass value_it = iter(prop.value) 309*2be282caSSimon Glass for phandle_cell, _ in zip(value_it, value_it): 3107581c01aSSimon Glass phandle = fdt_util.fdt32_to_cpu(phandle_cell) 311*2be282caSSimon Glass target_node = self._phandle_nodes[phandle] 3127581c01aSSimon Glass node.phandles.add(target_node) 3137581c01aSSimon Glass 3147581c01aSSimon Glass 315*2be282caSSimon Glass def generate_structs(self, structs): 3167581c01aSSimon Glass """Generate struct defintions for the platform data 3177581c01aSSimon Glass 3187581c01aSSimon Glass This writes out the body of a header file consisting of structure 3197581c01aSSimon Glass definitions for node in self._valid_nodes. See the documentation in 3207581c01aSSimon Glass README.of-plat for more information. 3217581c01aSSimon Glass """ 322*2be282caSSimon Glass self.out('#include <stdbool.h>\n') 323*2be282caSSimon Glass self.out('#include <libfdt.h>\n') 3247581c01aSSimon Glass 3257581c01aSSimon Glass # Output the struct definition 3267581c01aSSimon Glass for name in sorted(structs): 327*2be282caSSimon Glass self.out('struct %s%s {\n' % (STRUCT_PREFIX, name)) 3287581c01aSSimon Glass for pname in sorted(structs[name]): 3297581c01aSSimon Glass prop = structs[name][pname] 330*2be282caSSimon Glass if self.is_phandle(prop): 3317581c01aSSimon Glass # For phandles, include a reference to the target 332*2be282caSSimon Glass self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'), 333*2be282caSSimon Glass conv_name_to_c(prop.name), 3347581c01aSSimon Glass len(prop.value) / 2)) 3357581c01aSSimon Glass else: 3367581c01aSSimon Glass ptype = TYPE_NAMES[prop.type] 337*2be282caSSimon Glass self.out('\t%s%s' % (tab_to(2, ptype), 338*2be282caSSimon Glass conv_name_to_c(prop.name))) 339*2be282caSSimon Glass if isinstance(prop.value, list): 340*2be282caSSimon Glass self.out('[%d]' % len(prop.value)) 341*2be282caSSimon Glass self.out(';\n') 342*2be282caSSimon Glass self.out('};\n') 3437581c01aSSimon Glass 3447581c01aSSimon Glass for alias, struct_name in self._aliases.iteritems(): 345*2be282caSSimon Glass self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias, 3467581c01aSSimon Glass STRUCT_PREFIX, struct_name)) 3477581c01aSSimon Glass 348*2be282caSSimon Glass def output_node(self, node): 3497581c01aSSimon Glass """Output the C code for a node 3507581c01aSSimon Glass 3517581c01aSSimon Glass Args: 3527581c01aSSimon Glass node: node to output 3537581c01aSSimon Glass """ 354*2be282caSSimon Glass struct_name, _ = self.get_compat_name(node) 355*2be282caSSimon Glass var_name = conv_name_to_c(node.name) 356*2be282caSSimon Glass self.buf('static struct %s%s %s%s = {\n' % 3577581c01aSSimon Glass (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) 3587581c01aSSimon Glass for pname, prop in node.props.items(): 3597581c01aSSimon Glass if pname in PROP_IGNORE_LIST or pname[0] == '#': 3607581c01aSSimon Glass continue 361*2be282caSSimon Glass member_name = conv_name_to_c(prop.name) 362*2be282caSSimon Glass self.buf('\t%s= ' % tab_to(3, '.' + member_name)) 3637581c01aSSimon Glass 3647581c01aSSimon Glass # Special handling for lists 365*2be282caSSimon Glass if isinstance(prop.value, list): 366*2be282caSSimon Glass self.buf('{') 3677581c01aSSimon Glass vals = [] 3687581c01aSSimon Glass # For phandles, output a reference to the platform data 3697581c01aSSimon Glass # of the target node. 370*2be282caSSimon Glass if self.is_phandle(prop): 3717581c01aSSimon Glass # Process the list as pairs of (phandle, id) 372*2be282caSSimon Glass value_it = iter(prop.value) 373*2be282caSSimon Glass for phandle_cell, id_cell in zip(value_it, value_it): 3747581c01aSSimon Glass phandle = fdt_util.fdt32_to_cpu(phandle_cell) 375*2be282caSSimon Glass id_num = fdt_util.fdt32_to_cpu(id_cell) 376*2be282caSSimon Glass target_node = self._phandle_nodes[phandle] 377*2be282caSSimon Glass name = conv_name_to_c(target_node.name) 378*2be282caSSimon Glass vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num)) 3797581c01aSSimon Glass else: 3807581c01aSSimon Glass for val in prop.value: 381*2be282caSSimon Glass vals.append(self.get_value(prop.type, val)) 382*2be282caSSimon Glass self.buf(', '.join(vals)) 383*2be282caSSimon Glass self.buf('}') 3847581c01aSSimon Glass else: 385*2be282caSSimon Glass self.buf(self.get_value(prop.type, prop.value)) 386*2be282caSSimon Glass self.buf(',\n') 387*2be282caSSimon Glass self.buf('};\n') 3887581c01aSSimon Glass 3897581c01aSSimon Glass # Add a device declaration 390*2be282caSSimon Glass self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name) 391*2be282caSSimon Glass self.buf('\t.name\t\t= "%s",\n' % struct_name) 392*2be282caSSimon Glass self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name)) 393*2be282caSSimon Glass self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name)) 394*2be282caSSimon Glass self.buf('};\n') 395*2be282caSSimon Glass self.buf('\n') 3967581c01aSSimon Glass 397*2be282caSSimon Glass self.out(''.join(self.get_buf())) 3987581c01aSSimon Glass 399*2be282caSSimon Glass def generate_tables(self): 4007581c01aSSimon Glass """Generate device defintions for the platform data 4017581c01aSSimon Glass 4027581c01aSSimon Glass This writes out C platform data initialisation data and 4037581c01aSSimon Glass U_BOOT_DEVICE() declarations for each valid node. Where a node has 4047581c01aSSimon Glass multiple compatible strings, a #define is used to make them equivalent. 4057581c01aSSimon Glass 4067581c01aSSimon Glass See the documentation in doc/driver-model/of-plat.txt for more 4077581c01aSSimon Glass information. 4087581c01aSSimon Glass """ 409*2be282caSSimon Glass self.out('#include <common.h>\n') 410*2be282caSSimon Glass self.out('#include <dm.h>\n') 411*2be282caSSimon Glass self.out('#include <dt-structs.h>\n') 412*2be282caSSimon Glass self.out('\n') 4137581c01aSSimon Glass nodes_to_output = list(self._valid_nodes) 4147581c01aSSimon Glass 4157581c01aSSimon Glass # Keep outputing nodes until there is none left 4167581c01aSSimon Glass while nodes_to_output: 4177581c01aSSimon Glass node = nodes_to_output[0] 4187581c01aSSimon Glass # Output all the node's dependencies first 4197581c01aSSimon Glass for req_node in node.phandles: 4207581c01aSSimon Glass if req_node in nodes_to_output: 421*2be282caSSimon Glass self.output_node(req_node) 4227581c01aSSimon Glass nodes_to_output.remove(req_node) 423*2be282caSSimon Glass self.output_node(node) 4247581c01aSSimon Glass nodes_to_output.remove(node) 425