xref: /rk3399_rockchip-uboot/tools/dtoc/dtb_platdata.py (revision 2be282ca01dba237504fe2887fbd4539865093c3)
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