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