xref: /rk3399_rockchip-uboot/tools/dtoc/dtb_platdata.py (revision a28bfcc35587bf3d3f86eb49fb81c9570ddfcc4b)
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 Glassdef is_phandle(prop):
12056e0bbe0SSimon Glass    """Check if a node contains phandles
12156e0bbe0SSimon Glass
12256e0bbe0SSimon Glass    We have no reliable way of detecting whether a node uses a phandle
12356e0bbe0SSimon Glass    or not. As an interim measure, use a list of known property names.
12456e0bbe0SSimon Glass
12556e0bbe0SSimon Glass    Args:
12656e0bbe0SSimon Glass        prop: Prop object to check
12756e0bbe0SSimon Glass    Return:
12856e0bbe0SSimon Glass        True if the object value contains phandles, else False
12956e0bbe0SSimon Glass    """
13056e0bbe0SSimon Glass    if prop.name in ['clocks']:
13156e0bbe0SSimon Glass        return True
13256e0bbe0SSimon Glass    return False
13356e0bbe0SSimon Glass
13456e0bbe0SSimon Glass
1352be282caSSimon Glassclass DtbPlatdata(object):
1367581c01aSSimon Glass    """Provide a means to convert device tree binary data to platform data
1377581c01aSSimon Glass
1387581c01aSSimon Glass    The output of this process is C structures which can be used in space-
1397581c01aSSimon Glass    constrained encvironments where the ~3KB code overhead of device tree
1407581c01aSSimon Glass    code is not affordable.
1417581c01aSSimon Glass
1427581c01aSSimon Glass    Properties:
1432be282caSSimon Glass        _fdt: Fdt object, referencing the device tree
1447581c01aSSimon Glass        _dtb_fname: Filename of the input device tree binary file
1457581c01aSSimon Glass        _valid_nodes: A list of Node object with compatible strings
146e36024b0SSimon Glass        _include_disabled: true to include nodes marked status = "disabled"
1472be282caSSimon Glass        _phandle_nodes: A dict of nodes indexed by phandle number (1, 2...)
1487581c01aSSimon Glass        _outfile: The current output file (sys.stdout or a real file)
1497581c01aSSimon Glass        _lines: Stashed list of output lines for outputting in the future
1502be282caSSimon Glass        _phandle_nodes: A dict of Nodes indexed by phandle (an integer)
1517581c01aSSimon Glass    """
152e36024b0SSimon Glass    def __init__(self, dtb_fname, include_disabled):
1532be282caSSimon Glass        self._fdt = None
1547581c01aSSimon Glass        self._dtb_fname = dtb_fname
1557581c01aSSimon Glass        self._valid_nodes = None
156e36024b0SSimon Glass        self._include_disabled = include_disabled
1572be282caSSimon Glass        self._phandle_nodes = {}
1587581c01aSSimon Glass        self._outfile = None
1597581c01aSSimon Glass        self._lines = []
1607581c01aSSimon Glass        self._aliases = {}
1617581c01aSSimon Glass
1622be282caSSimon Glass    def setup_output(self, fname):
1637581c01aSSimon Glass        """Set up the output destination
1647581c01aSSimon Glass
1652be282caSSimon Glass        Once this is done, future calls to self.out() will output to this
1667581c01aSSimon Glass        file.
1677581c01aSSimon Glass
1687581c01aSSimon Glass        Args:
1697581c01aSSimon Glass            fname: Filename to send output to, or '-' for stdout
1707581c01aSSimon Glass        """
1717581c01aSSimon Glass        if fname == '-':
1727581c01aSSimon Glass            self._outfile = sys.stdout
1737581c01aSSimon Glass        else:
1747581c01aSSimon Glass            self._outfile = open(fname, 'w')
1757581c01aSSimon Glass
1762be282caSSimon Glass    def out(self, line):
1777581c01aSSimon Glass        """Output a string to the output file
1787581c01aSSimon Glass
1797581c01aSSimon Glass        Args:
1802be282caSSimon Glass            line: String to output
1817581c01aSSimon Glass        """
1822be282caSSimon Glass        self._outfile.write(line)
1837581c01aSSimon Glass
1842be282caSSimon Glass    def buf(self, line):
1857581c01aSSimon Glass        """Buffer up a string to send later
1867581c01aSSimon Glass
1877581c01aSSimon Glass        Args:
1882be282caSSimon Glass            line: String to add to our 'buffer' list
1897581c01aSSimon Glass        """
1902be282caSSimon Glass        self._lines.append(line)
1917581c01aSSimon Glass
1922be282caSSimon Glass    def get_buf(self):
1937581c01aSSimon Glass        """Get the contents of the output buffer, and clear it
1947581c01aSSimon Glass
1957581c01aSSimon Glass        Returns:
1967581c01aSSimon Glass            The output buffer, which is then cleared for future use
1977581c01aSSimon Glass        """
1987581c01aSSimon Glass        lines = self._lines
1997581c01aSSimon Glass        self._lines = []
2007581c01aSSimon Glass        return lines
2017581c01aSSimon Glass
2022be282caSSimon Glass    def scan_dtb(self):
203f1a7ba1dSAnatolij Gustschin        """Scan the device tree to obtain a tree of nodes and properties
2047581c01aSSimon Glass
2052be282caSSimon Glass        Once this is done, self._fdt.GetRoot() can be called to obtain the
2067581c01aSSimon Glass        device tree root node, and progress from there.
2077581c01aSSimon Glass        """
2082be282caSSimon Glass        self._fdt = fdt.FdtScan(self._dtb_fname)
2097581c01aSSimon Glass
2102be282caSSimon Glass    def scan_node(self, root):
2112be282caSSimon Glass        """Scan a node and subnodes to build a tree of node and phandle info
2122be282caSSimon Glass
2132be282caSSimon Glass        This adds each node to self._valid_nodes and each phandle to
2142be282caSSimon Glass        self._phandle_nodes.
2152be282caSSimon Glass
2162be282caSSimon Glass        Args:
2172be282caSSimon Glass            root: Root node for scan
2182be282caSSimon Glass        """
2197581c01aSSimon Glass        for node in root.subnodes:
2207581c01aSSimon Glass            if 'compatible' in node.props:
2217581c01aSSimon Glass                status = node.props.get('status')
222e36024b0SSimon Glass                if (not self._include_disabled and not status or
2237581c01aSSimon Glass                        status.value != 'disabled'):
2247581c01aSSimon Glass                    self._valid_nodes.append(node)
2257581c01aSSimon Glass                    phandle_prop = node.props.get('phandle')
2267581c01aSSimon Glass                    if phandle_prop:
2277581c01aSSimon Glass                        phandle = phandle_prop.GetPhandle()
2282be282caSSimon Glass                        self._phandle_nodes[phandle] = node
2297581c01aSSimon Glass
2307581c01aSSimon Glass            # recurse to handle any subnodes
2312be282caSSimon Glass            self.scan_node(node)
2327581c01aSSimon Glass
2332be282caSSimon Glass    def scan_tree(self):
2347581c01aSSimon Glass        """Scan the device tree for useful information
2357581c01aSSimon Glass
2367581c01aSSimon Glass        This fills in the following properties:
2372be282caSSimon Glass            _phandle_nodes: A dict of Nodes indexed by phandle (an integer)
2387581c01aSSimon Glass            _valid_nodes: A list of nodes we wish to consider include in the
2397581c01aSSimon Glass                platform data
2407581c01aSSimon Glass        """
2412be282caSSimon Glass        self._phandle_nodes = {}
2427581c01aSSimon Glass        self._valid_nodes = []
2432be282caSSimon Glass        return self.scan_node(self._fdt.GetRoot())
2447581c01aSSimon Glass
245*a28bfcc3SSimon Glass    @staticmethod
246*a28bfcc3SSimon Glass    def get_num_cells(node):
247*a28bfcc3SSimon Glass        """Get the number of cells in addresses and sizes for this node
248*a28bfcc3SSimon Glass
249*a28bfcc3SSimon Glass        Args:
250*a28bfcc3SSimon Glass            node: Node to check
251*a28bfcc3SSimon Glass
252*a28bfcc3SSimon Glass        Returns:
253*a28bfcc3SSimon Glass            Tuple:
254*a28bfcc3SSimon Glass                Number of address cells for this node
255*a28bfcc3SSimon Glass                Number of size cells for this node
256*a28bfcc3SSimon Glass        """
257*a28bfcc3SSimon Glass        parent = node.parent
258*a28bfcc3SSimon Glass        na, ns = 2, 2
259*a28bfcc3SSimon Glass        if parent:
260*a28bfcc3SSimon Glass            na_prop = parent.props.get('#address-cells')
261*a28bfcc3SSimon Glass            ns_prop = parent.props.get('#size-cells')
262*a28bfcc3SSimon Glass            if na_prop:
263*a28bfcc3SSimon Glass                na = fdt_util.fdt32_to_cpu(na_prop.value)
264*a28bfcc3SSimon Glass            if ns_prop:
265*a28bfcc3SSimon Glass                ns = fdt_util.fdt32_to_cpu(ns_prop.value)
266*a28bfcc3SSimon Glass        return na, ns
267*a28bfcc3SSimon Glass
268*a28bfcc3SSimon Glass    def scan_reg_sizes(self):
269*a28bfcc3SSimon Glass        """Scan for 64-bit 'reg' properties and update the values
270*a28bfcc3SSimon Glass
271*a28bfcc3SSimon Glass        This finds 'reg' properties with 64-bit data and converts the value to
272*a28bfcc3SSimon Glass        an array of 64-values. This allows it to be output in a way that the
273*a28bfcc3SSimon Glass        C code can read.
274*a28bfcc3SSimon Glass        """
275*a28bfcc3SSimon Glass        for node in self._valid_nodes:
276*a28bfcc3SSimon Glass            reg = node.props.get('reg')
277*a28bfcc3SSimon Glass            if not reg:
278*a28bfcc3SSimon Glass                continue
279*a28bfcc3SSimon Glass            na, ns = self.get_num_cells(node)
280*a28bfcc3SSimon Glass            total = na + ns
281*a28bfcc3SSimon Glass
282*a28bfcc3SSimon Glass            if reg.type != fdt.TYPE_INT:
283*a28bfcc3SSimon Glass                raise ValueError("Node '%s' reg property is not an int")
284*a28bfcc3SSimon Glass            if len(reg.value) % total:
285*a28bfcc3SSimon Glass                raise ValueError("Node '%s' reg property has %d cells "
286*a28bfcc3SSimon Glass                        'which is not a multiple of na + ns = %d + %d)' %
287*a28bfcc3SSimon Glass                        (node.name, len(reg.value), na, ns))
288*a28bfcc3SSimon Glass            reg.na = na
289*a28bfcc3SSimon Glass            reg.ns = ns
290*a28bfcc3SSimon Glass            if na != 1 or ns != 1:
291*a28bfcc3SSimon Glass                reg.type = fdt.TYPE_INT64
292*a28bfcc3SSimon Glass                i = 0
293*a28bfcc3SSimon Glass                new_value = []
294*a28bfcc3SSimon Glass                val = reg.value
295*a28bfcc3SSimon Glass                if not isinstance(val, list):
296*a28bfcc3SSimon Glass                    val = [val]
297*a28bfcc3SSimon Glass                while i < len(val):
298*a28bfcc3SSimon Glass                    addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
299*a28bfcc3SSimon Glass                    i += na
300*a28bfcc3SSimon Glass                    size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
301*a28bfcc3SSimon Glass                    i += ns
302*a28bfcc3SSimon Glass                    new_value += [addr, size]
303*a28bfcc3SSimon Glass                reg.value = new_value
304*a28bfcc3SSimon Glass
3052be282caSSimon Glass    def scan_structs(self):
3067581c01aSSimon Glass        """Scan the device tree building up the C structures we will use.
3077581c01aSSimon Glass
3087581c01aSSimon Glass        Build a dict keyed by C struct name containing a dict of Prop
3097581c01aSSimon Glass        object for each struct field (keyed by property name). Where the
3107581c01aSSimon Glass        same struct appears multiple times, try to use the 'widest'
3117581c01aSSimon Glass        property, i.e. the one with a type which can express all others.
3127581c01aSSimon Glass
3137581c01aSSimon Glass        Once the widest property is determined, all other properties are
3147581c01aSSimon Glass        updated to match that width.
3157581c01aSSimon Glass        """
3167581c01aSSimon Glass        structs = {}
3177581c01aSSimon Glass        for node in self._valid_nodes:
31856e0bbe0SSimon Glass            node_name, _ = get_compat_name(node)
3197581c01aSSimon Glass            fields = {}
3207581c01aSSimon Glass
3217581c01aSSimon Glass            # Get a list of all the valid properties in this node.
3227581c01aSSimon Glass            for name, prop in node.props.items():
3237581c01aSSimon Glass                if name not in PROP_IGNORE_LIST and name[0] != '#':
3247581c01aSSimon Glass                    fields[name] = copy.deepcopy(prop)
3257581c01aSSimon Glass
3267581c01aSSimon Glass            # If we've seen this node_name before, update the existing struct.
3277581c01aSSimon Glass            if node_name in structs:
3287581c01aSSimon Glass                struct = structs[node_name]
3297581c01aSSimon Glass                for name, prop in fields.items():
3307581c01aSSimon Glass                    oldprop = struct.get(name)
3317581c01aSSimon Glass                    if oldprop:
3327581c01aSSimon Glass                        oldprop.Widen(prop)
3337581c01aSSimon Glass                    else:
3347581c01aSSimon Glass                        struct[name] = prop
3357581c01aSSimon Glass
3367581c01aSSimon Glass            # Otherwise store this as a new struct.
3377581c01aSSimon Glass            else:
3387581c01aSSimon Glass                structs[node_name] = fields
3397581c01aSSimon Glass
3407581c01aSSimon Glass        upto = 0
3417581c01aSSimon Glass        for node in self._valid_nodes:
34256e0bbe0SSimon Glass            node_name, _ = get_compat_name(node)
3437581c01aSSimon Glass            struct = structs[node_name]
3447581c01aSSimon Glass            for name, prop in node.props.items():
3457581c01aSSimon Glass                if name not in PROP_IGNORE_LIST and name[0] != '#':
3467581c01aSSimon Glass                    prop.Widen(struct[name])
3477581c01aSSimon Glass            upto += 1
3487581c01aSSimon Glass
34956e0bbe0SSimon Glass            struct_name, aliases = get_compat_name(node)
3507581c01aSSimon Glass            for alias in aliases:
3517581c01aSSimon Glass                self._aliases[alias] = struct_name
3527581c01aSSimon Glass
3537581c01aSSimon Glass        return structs
3547581c01aSSimon Glass
3552be282caSSimon Glass    def scan_phandles(self):
3567581c01aSSimon Glass        """Figure out what phandles each node uses
3577581c01aSSimon Glass
3587581c01aSSimon Glass        We need to be careful when outputing nodes that use phandles since
3597581c01aSSimon Glass        they must come after the declaration of the phandles in the C file.
3607581c01aSSimon Glass        Otherwise we get a compiler error since the phandle struct is not yet
3617581c01aSSimon Glass        declared.
3627581c01aSSimon Glass
3637581c01aSSimon Glass        This function adds to each node a list of phandle nodes that the node
3647581c01aSSimon Glass        depends on. This allows us to output things in the right order.
3657581c01aSSimon Glass        """
3667581c01aSSimon Glass        for node in self._valid_nodes:
3677581c01aSSimon Glass            node.phandles = set()
3687581c01aSSimon Glass            for pname, prop in node.props.items():
3697581c01aSSimon Glass                if pname in PROP_IGNORE_LIST or pname[0] == '#':
3707581c01aSSimon Glass                    continue
3712be282caSSimon Glass                if isinstance(prop.value, list):
37256e0bbe0SSimon Glass                    if is_phandle(prop):
3737581c01aSSimon Glass                        # Process the list as pairs of (phandle, id)
3742be282caSSimon Glass                        value_it = iter(prop.value)
3752be282caSSimon Glass                        for phandle_cell, _ in zip(value_it, value_it):
3767581c01aSSimon Glass                            phandle = fdt_util.fdt32_to_cpu(phandle_cell)
3772be282caSSimon Glass                            target_node = self._phandle_nodes[phandle]
3787581c01aSSimon Glass                            node.phandles.add(target_node)
3797581c01aSSimon Glass
3807581c01aSSimon Glass
3812be282caSSimon Glass    def generate_structs(self, structs):
3827581c01aSSimon Glass        """Generate struct defintions for the platform data
3837581c01aSSimon Glass
3847581c01aSSimon Glass        This writes out the body of a header file consisting of structure
3857581c01aSSimon Glass        definitions for node in self._valid_nodes. See the documentation in
3867581c01aSSimon Glass        README.of-plat for more information.
3877581c01aSSimon Glass        """
3882be282caSSimon Glass        self.out('#include <stdbool.h>\n')
3892be282caSSimon Glass        self.out('#include <libfdt.h>\n')
3907581c01aSSimon Glass
3917581c01aSSimon Glass        # Output the struct definition
3927581c01aSSimon Glass        for name in sorted(structs):
3932be282caSSimon Glass            self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
3947581c01aSSimon Glass            for pname in sorted(structs[name]):
3957581c01aSSimon Glass                prop = structs[name][pname]
39656e0bbe0SSimon Glass                if is_phandle(prop):
3977581c01aSSimon Glass                    # For phandles, include a reference to the target
3982be282caSSimon Glass                    self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'),
3992be282caSSimon Glass                                             conv_name_to_c(prop.name),
4007581c01aSSimon Glass                                             len(prop.value) / 2))
4017581c01aSSimon Glass                else:
4027581c01aSSimon Glass                    ptype = TYPE_NAMES[prop.type]
4032be282caSSimon Glass                    self.out('\t%s%s' % (tab_to(2, ptype),
4042be282caSSimon Glass                                         conv_name_to_c(prop.name)))
4052be282caSSimon Glass                    if isinstance(prop.value, list):
4062be282caSSimon Glass                        self.out('[%d]' % len(prop.value))
4072be282caSSimon Glass                self.out(';\n')
4082be282caSSimon Glass            self.out('};\n')
4097581c01aSSimon Glass
4107581c01aSSimon Glass        for alias, struct_name in self._aliases.iteritems():
4112be282caSSimon Glass            self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
4127581c01aSSimon Glass                                             STRUCT_PREFIX, struct_name))
4137581c01aSSimon Glass
4142be282caSSimon Glass    def output_node(self, node):
4157581c01aSSimon Glass        """Output the C code for a node
4167581c01aSSimon Glass
4177581c01aSSimon Glass        Args:
4187581c01aSSimon Glass            node: node to output
4197581c01aSSimon Glass        """
42056e0bbe0SSimon Glass        struct_name, _ = get_compat_name(node)
4212be282caSSimon Glass        var_name = conv_name_to_c(node.name)
4222be282caSSimon Glass        self.buf('static struct %s%s %s%s = {\n' %
4237581c01aSSimon Glass                 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
4247581c01aSSimon Glass        for pname, prop in node.props.items():
4257581c01aSSimon Glass            if pname in PROP_IGNORE_LIST or pname[0] == '#':
4267581c01aSSimon Glass                continue
4272be282caSSimon Glass            member_name = conv_name_to_c(prop.name)
4282be282caSSimon Glass            self.buf('\t%s= ' % tab_to(3, '.' + member_name))
4297581c01aSSimon Glass
4307581c01aSSimon Glass            # Special handling for lists
4312be282caSSimon Glass            if isinstance(prop.value, list):
4322be282caSSimon Glass                self.buf('{')
4337581c01aSSimon Glass                vals = []
4347581c01aSSimon Glass                # For phandles, output a reference to the platform data
4357581c01aSSimon Glass                # of the target node.
43656e0bbe0SSimon Glass                if is_phandle(prop):
4377581c01aSSimon Glass                    # Process the list as pairs of (phandle, id)
4382be282caSSimon Glass                    value_it = iter(prop.value)
4392be282caSSimon Glass                    for phandle_cell, id_cell in zip(value_it, value_it):
4407581c01aSSimon Glass                        phandle = fdt_util.fdt32_to_cpu(phandle_cell)
4412be282caSSimon Glass                        id_num = fdt_util.fdt32_to_cpu(id_cell)
4422be282caSSimon Glass                        target_node = self._phandle_nodes[phandle]
4432be282caSSimon Glass                        name = conv_name_to_c(target_node.name)
4442be282caSSimon Glass                        vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num))
4457581c01aSSimon Glass                else:
4467581c01aSSimon Glass                    for val in prop.value:
44756e0bbe0SSimon Glass                        vals.append(get_value(prop.type, val))
44812a972efSSimon Glass
44912a972efSSimon Glass                # Put 8 values per line to avoid very long lines.
45012a972efSSimon Glass                for i in xrange(0, len(vals), 8):
45112a972efSSimon Glass                    if i:
45212a972efSSimon Glass                        self.buf(',\n\t\t')
45312a972efSSimon Glass                    self.buf(', '.join(vals[i:i + 8]))
4542be282caSSimon Glass                self.buf('}')
4557581c01aSSimon Glass            else:
45656e0bbe0SSimon Glass                self.buf(get_value(prop.type, prop.value))
4572be282caSSimon Glass            self.buf(',\n')
4582be282caSSimon Glass        self.buf('};\n')
4597581c01aSSimon Glass
4607581c01aSSimon Glass        # Add a device declaration
4612be282caSSimon Glass        self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
4622be282caSSimon Glass        self.buf('\t.name\t\t= "%s",\n' % struct_name)
4632be282caSSimon Glass        self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
4642be282caSSimon Glass        self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
4652be282caSSimon Glass        self.buf('};\n')
4662be282caSSimon Glass        self.buf('\n')
4677581c01aSSimon Glass
4682be282caSSimon Glass        self.out(''.join(self.get_buf()))
4697581c01aSSimon Glass
4702be282caSSimon Glass    def generate_tables(self):
4717581c01aSSimon Glass        """Generate device defintions for the platform data
4727581c01aSSimon Glass
4737581c01aSSimon Glass        This writes out C platform data initialisation data and
4747581c01aSSimon Glass        U_BOOT_DEVICE() declarations for each valid node. Where a node has
4757581c01aSSimon Glass        multiple compatible strings, a #define is used to make them equivalent.
4767581c01aSSimon Glass
4777581c01aSSimon Glass        See the documentation in doc/driver-model/of-plat.txt for more
4787581c01aSSimon Glass        information.
4797581c01aSSimon Glass        """
4802be282caSSimon Glass        self.out('#include <common.h>\n')
4812be282caSSimon Glass        self.out('#include <dm.h>\n')
4822be282caSSimon Glass        self.out('#include <dt-structs.h>\n')
4832be282caSSimon Glass        self.out('\n')
4847581c01aSSimon Glass        nodes_to_output = list(self._valid_nodes)
4857581c01aSSimon Glass
4867581c01aSSimon Glass        # Keep outputing nodes until there is none left
4877581c01aSSimon Glass        while nodes_to_output:
4887581c01aSSimon Glass            node = nodes_to_output[0]
4897581c01aSSimon Glass            # Output all the node's dependencies first
4907581c01aSSimon Glass            for req_node in node.phandles:
4917581c01aSSimon Glass                if req_node in nodes_to_output:
4922be282caSSimon Glass                    self.output_node(req_node)
4937581c01aSSimon Glass                    nodes_to_output.remove(req_node)
4942be282caSSimon Glass            self.output_node(node)
4957581c01aSSimon Glass            nodes_to_output.remove(node)
496fa0ea5b0SSimon Glass
497fa0ea5b0SSimon Glass
498fa0ea5b0SSimon Glassdef run_steps(args, dtb_file, include_disabled, output):
499fa0ea5b0SSimon Glass    """Run all the steps of the dtoc tool
500fa0ea5b0SSimon Glass
501fa0ea5b0SSimon Glass    Args:
502fa0ea5b0SSimon Glass        args: List of non-option arguments provided to the problem
503fa0ea5b0SSimon Glass        dtb_file: Filename of dtb file to process
504fa0ea5b0SSimon Glass        include_disabled: True to include disabled nodes
505fa0ea5b0SSimon Glass        output: Name of output file
506fa0ea5b0SSimon Glass    """
507fa0ea5b0SSimon Glass    if not args:
508fa0ea5b0SSimon Glass        raise ValueError('Please specify a command: struct, platdata')
509fa0ea5b0SSimon Glass
510fa0ea5b0SSimon Glass    plat = DtbPlatdata(dtb_file, include_disabled)
511fa0ea5b0SSimon Glass    plat.scan_dtb()
512fa0ea5b0SSimon Glass    plat.scan_tree()
513*a28bfcc3SSimon Glass    plat.scan_reg_sizes()
514fa0ea5b0SSimon Glass    plat.setup_output(output)
515fa0ea5b0SSimon Glass    structs = plat.scan_structs()
516fa0ea5b0SSimon Glass    plat.scan_phandles()
517fa0ea5b0SSimon Glass
518fa0ea5b0SSimon Glass    for cmd in args[0].split(','):
519fa0ea5b0SSimon Glass        if cmd == 'struct':
520fa0ea5b0SSimon Glass            plat.generate_structs(structs)
521fa0ea5b0SSimon Glass        elif cmd == 'platdata':
522fa0ea5b0SSimon Glass            plat.generate_tables()
523fa0ea5b0SSimon Glass        else:
524fa0ea5b0SSimon Glass            raise ValueError("Unknown command '%s': (use: struct, platdata)" %
525fa0ea5b0SSimon Glass                             cmd)
526