xref: /rk3399_rockchip-uboot/tools/dtoc/dtb_platdata.py (revision 3a40acd42e66522b944d6f1a6aa3297771c9fa65)
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
15cb3f9bf4SSimon Glassimport collections
167581c01aSSimon Glassimport copy
172be282caSSimon Glassimport sys
187581c01aSSimon Glass
197581c01aSSimon Glassimport fdt
207581c01aSSimon Glassimport fdt_util
217581c01aSSimon Glass
227581c01aSSimon Glass# When we see these properties we ignore them - i.e. do not create a structure member
237581c01aSSimon GlassPROP_IGNORE_LIST = [
247581c01aSSimon Glass    '#address-cells',
257581c01aSSimon Glass    '#gpio-cells',
267581c01aSSimon Glass    '#size-cells',
277581c01aSSimon Glass    'compatible',
287581c01aSSimon Glass    'linux,phandle',
297581c01aSSimon Glass    "status",
307581c01aSSimon Glass    'phandle',
317581c01aSSimon Glass    'u-boot,dm-pre-reloc',
327581c01aSSimon Glass    'u-boot,dm-tpl',
337581c01aSSimon Glass    'u-boot,dm-spl',
347581c01aSSimon Glass]
357581c01aSSimon Glass
367581c01aSSimon Glass# C type declarations for the tyues we support
377581c01aSSimon GlassTYPE_NAMES = {
387581c01aSSimon Glass    fdt.TYPE_INT: 'fdt32_t',
397581c01aSSimon Glass    fdt.TYPE_BYTE: 'unsigned char',
407581c01aSSimon Glass    fdt.TYPE_STRING: 'const char *',
417581c01aSSimon Glass    fdt.TYPE_BOOL: 'bool',
42ef2715f4SSimon Glass    fdt.TYPE_INT64: 'fdt64_t',
432be282caSSimon Glass}
447581c01aSSimon Glass
457581c01aSSimon GlassSTRUCT_PREFIX = 'dtd_'
467581c01aSSimon GlassVAL_PREFIX = 'dtv_'
477581c01aSSimon Glass
48cb3f9bf4SSimon Glass# This holds information about a property which includes phandles.
49cb3f9bf4SSimon Glass#
50cb3f9bf4SSimon Glass# max_args: integer: Maximum number or arguments that any phandle uses (int).
51cb3f9bf4SSimon Glass# args: Number of args for each phandle in the property. The total number of
52cb3f9bf4SSimon Glass#     phandles is len(args). This is a list of integers.
53cb3f9bf4SSimon GlassPhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
54cb3f9bf4SSimon Glass
55cb3f9bf4SSimon Glass
562be282caSSimon Glassdef conv_name_to_c(name):
577581c01aSSimon Glass    """Convert a device-tree name to a C identifier
587581c01aSSimon Glass
5930107b08SSimon Glass    This uses multiple replace() calls instead of re.sub() since it is faster
6030107b08SSimon Glass    (400ms for 1m calls versus 1000ms for the 're' version).
6130107b08SSimon Glass
627581c01aSSimon Glass    Args:
637581c01aSSimon Glass        name:   Name to convert
647581c01aSSimon Glass    Return:
657581c01aSSimon Glass        String containing the C version of this name
667581c01aSSimon Glass    """
672be282caSSimon Glass    new = name.replace('@', '_at_')
682be282caSSimon Glass    new = new.replace('-', '_')
692be282caSSimon Glass    new = new.replace(',', '_')
702be282caSSimon Glass    new = new.replace('.', '_')
712be282caSSimon Glass    return new
727581c01aSSimon Glass
732be282caSSimon Glassdef tab_to(num_tabs, line):
742be282caSSimon Glass    """Append tabs to a line of text to reach a tab stop.
757581c01aSSimon Glass
762be282caSSimon Glass    Args:
772be282caSSimon Glass        num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
782be282caSSimon Glass        line: Line of text to append to
792be282caSSimon Glass
802be282caSSimon Glass    Returns:
812be282caSSimon Glass        line with the correct number of tabs appeneded. If the line already
822be282caSSimon Glass        extends past that tab stop then a single space is appended.
832be282caSSimon Glass    """
842be282caSSimon Glass    if len(line) >= num_tabs * 8:
852be282caSSimon Glass        return line + ' '
862be282caSSimon Glass    return line + '\t' * (num_tabs - len(line) // 8)
872be282caSSimon Glass
8856e0bbe0SSimon Glassdef get_value(ftype, value):
8956e0bbe0SSimon Glass    """Get a value as a C expression
9056e0bbe0SSimon Glass
9156e0bbe0SSimon Glass    For integers this returns a byte-swapped (little-endian) hex string
9256e0bbe0SSimon Glass    For bytes this returns a hex string, e.g. 0x12
9356e0bbe0SSimon Glass    For strings this returns a literal string enclosed in quotes
9456e0bbe0SSimon Glass    For booleans this return 'true'
9556e0bbe0SSimon Glass
9656e0bbe0SSimon Glass    Args:
9756e0bbe0SSimon Glass        type: Data type (fdt_util)
9856e0bbe0SSimon Glass        value: Data value, as a string of bytes
9956e0bbe0SSimon Glass    """
10056e0bbe0SSimon Glass    if ftype == fdt.TYPE_INT:
10156e0bbe0SSimon Glass        return '%#x' % fdt_util.fdt32_to_cpu(value)
10256e0bbe0SSimon Glass    elif ftype == fdt.TYPE_BYTE:
10356e0bbe0SSimon Glass        return '%#x' % ord(value[0])
10456e0bbe0SSimon Glass    elif ftype == fdt.TYPE_STRING:
10556e0bbe0SSimon Glass        return '"%s"' % value
10656e0bbe0SSimon Glass    elif ftype == fdt.TYPE_BOOL:
10756e0bbe0SSimon Glass        return 'true'
108ef2715f4SSimon Glass    elif ftype == fdt.TYPE_INT64:
109ef2715f4SSimon Glass        return '%#x' % value
11056e0bbe0SSimon Glass
11156e0bbe0SSimon Glassdef get_compat_name(node):
11256e0bbe0SSimon Glass    """Get a node's first compatible string as a C identifier
11356e0bbe0SSimon Glass
11456e0bbe0SSimon Glass    Args:
11556e0bbe0SSimon Glass        node: Node object to check
11656e0bbe0SSimon Glass    Return:
11756e0bbe0SSimon Glass        Tuple:
11856e0bbe0SSimon Glass            C identifier for the first compatible string
11956e0bbe0SSimon Glass            List of C identifiers for all the other compatible strings
12056e0bbe0SSimon Glass                (possibly empty)
12156e0bbe0SSimon Glass    """
12256e0bbe0SSimon Glass    compat = node.props['compatible'].value
12356e0bbe0SSimon Glass    aliases = []
12456e0bbe0SSimon Glass    if isinstance(compat, list):
12556e0bbe0SSimon Glass        compat, aliases = compat[0], compat[1:]
12656e0bbe0SSimon Glass    return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases]
12756e0bbe0SSimon Glass
12856e0bbe0SSimon Glass
1292be282caSSimon Glassclass DtbPlatdata(object):
1307581c01aSSimon Glass    """Provide a means to convert device tree binary data to platform data
1317581c01aSSimon Glass
1327581c01aSSimon Glass    The output of this process is C structures which can be used in space-
1337581c01aSSimon Glass    constrained encvironments where the ~3KB code overhead of device tree
1347581c01aSSimon Glass    code is not affordable.
1357581c01aSSimon Glass
1367581c01aSSimon Glass    Properties:
1372be282caSSimon Glass        _fdt: Fdt object, referencing the device tree
1387581c01aSSimon Glass        _dtb_fname: Filename of the input device tree binary file
1397581c01aSSimon Glass        _valid_nodes: A list of Node object with compatible strings
140e36024b0SSimon Glass        _include_disabled: true to include nodes marked status = "disabled"
1417581c01aSSimon Glass        _outfile: The current output file (sys.stdout or a real file)
1427581c01aSSimon Glass        _lines: Stashed list of output lines for outputting in the future
1437581c01aSSimon Glass    """
144e36024b0SSimon Glass    def __init__(self, dtb_fname, include_disabled):
1452be282caSSimon Glass        self._fdt = None
1467581c01aSSimon Glass        self._dtb_fname = dtb_fname
1477581c01aSSimon Glass        self._valid_nodes = None
148e36024b0SSimon Glass        self._include_disabled = include_disabled
1497581c01aSSimon Glass        self._outfile = None
1507581c01aSSimon Glass        self._lines = []
1517581c01aSSimon Glass        self._aliases = {}
1527581c01aSSimon Glass
1532be282caSSimon Glass    def setup_output(self, fname):
1547581c01aSSimon Glass        """Set up the output destination
1557581c01aSSimon Glass
1562be282caSSimon Glass        Once this is done, future calls to self.out() will output to this
1577581c01aSSimon Glass        file.
1587581c01aSSimon Glass
1597581c01aSSimon Glass        Args:
1607581c01aSSimon Glass            fname: Filename to send output to, or '-' for stdout
1617581c01aSSimon Glass        """
1627581c01aSSimon Glass        if fname == '-':
1637581c01aSSimon Glass            self._outfile = sys.stdout
1647581c01aSSimon Glass        else:
1657581c01aSSimon Glass            self._outfile = open(fname, 'w')
1667581c01aSSimon Glass
1672be282caSSimon Glass    def out(self, line):
1687581c01aSSimon Glass        """Output a string to the output file
1697581c01aSSimon Glass
1707581c01aSSimon Glass        Args:
1712be282caSSimon Glass            line: String to output
1727581c01aSSimon Glass        """
1732be282caSSimon Glass        self._outfile.write(line)
1747581c01aSSimon Glass
1752be282caSSimon Glass    def buf(self, line):
1767581c01aSSimon Glass        """Buffer up a string to send later
1777581c01aSSimon Glass
1787581c01aSSimon Glass        Args:
1792be282caSSimon Glass            line: String to add to our 'buffer' list
1807581c01aSSimon Glass        """
1812be282caSSimon Glass        self._lines.append(line)
1827581c01aSSimon Glass
1832be282caSSimon Glass    def get_buf(self):
1847581c01aSSimon Glass        """Get the contents of the output buffer, and clear it
1857581c01aSSimon Glass
1867581c01aSSimon Glass        Returns:
1877581c01aSSimon Glass            The output buffer, which is then cleared for future use
1887581c01aSSimon Glass        """
1897581c01aSSimon Glass        lines = self._lines
1907581c01aSSimon Glass        self._lines = []
1917581c01aSSimon Glass        return lines
1927581c01aSSimon Glass
193cb3f9bf4SSimon Glass    def get_phandle_argc(self, prop, node_name):
1947088d44bSSimon Glass        """Check if a node contains phandles
1957088d44bSSimon Glass
1967088d44bSSimon Glass        We have no reliable way of detecting whether a node uses a phandle
1977088d44bSSimon Glass        or not. As an interim measure, use a list of known property names.
1987088d44bSSimon Glass
1997088d44bSSimon Glass        Args:
2007088d44bSSimon Glass            prop: Prop object to check
2017088d44bSSimon Glass        Return:
202cb3f9bf4SSimon Glass            Number of argument cells is this is a phandle, else None
2037088d44bSSimon Glass        """
2047088d44bSSimon Glass        if prop.name in ['clocks']:
205cb3f9bf4SSimon Glass            val = prop.value
206cb3f9bf4SSimon Glass            if not isinstance(val, list):
207cb3f9bf4SSimon Glass                val = [val]
208cb3f9bf4SSimon Glass            i = 0
209cb3f9bf4SSimon Glass
210cb3f9bf4SSimon Glass            max_args = 0
211cb3f9bf4SSimon Glass            args = []
212cb3f9bf4SSimon Glass            while i < len(val):
213cb3f9bf4SSimon Glass                phandle = fdt_util.fdt32_to_cpu(val[i])
214cb3f9bf4SSimon Glass                target = self._fdt.phandle_to_node.get(phandle)
215cb3f9bf4SSimon Glass                if not target:
216cb3f9bf4SSimon Glass                    raise ValueError("Cannot parse '%s' in node '%s'" %
217cb3f9bf4SSimon Glass                                     (prop.name, node_name))
218cb3f9bf4SSimon Glass                prop_name = '#clock-cells'
219cb3f9bf4SSimon Glass                cells = target.props.get(prop_name)
220cb3f9bf4SSimon Glass                if not cells:
221cb3f9bf4SSimon Glass                    raise ValueError("Node '%s' has no '%s' property" %
222cb3f9bf4SSimon Glass                            (target.name, prop_name))
223cb3f9bf4SSimon Glass                num_args = fdt_util.fdt32_to_cpu(cells.value)
224cb3f9bf4SSimon Glass                max_args = max(max_args, num_args)
225cb3f9bf4SSimon Glass                args.append(num_args)
226cb3f9bf4SSimon Glass                i += 1 + num_args
227cb3f9bf4SSimon Glass            return PhandleInfo(max_args, args)
228cb3f9bf4SSimon Glass        return None
2297088d44bSSimon Glass
2302be282caSSimon Glass    def scan_dtb(self):
231f1a7ba1dSAnatolij Gustschin        """Scan the device tree to obtain a tree of nodes and properties
2327581c01aSSimon Glass
2332be282caSSimon Glass        Once this is done, self._fdt.GetRoot() can be called to obtain the
2347581c01aSSimon Glass        device tree root node, and progress from there.
2357581c01aSSimon Glass        """
2362be282caSSimon Glass        self._fdt = fdt.FdtScan(self._dtb_fname)
2377581c01aSSimon Glass
2382be282caSSimon Glass    def scan_node(self, root):
2392be282caSSimon Glass        """Scan a node and subnodes to build a tree of node and phandle info
2402be282caSSimon Glass
2410ac13c21SSimon Glass        This adds each node to self._valid_nodes.
2422be282caSSimon Glass
2432be282caSSimon Glass        Args:
2442be282caSSimon Glass            root: Root node for scan
2452be282caSSimon Glass        """
2467581c01aSSimon Glass        for node in root.subnodes:
2477581c01aSSimon Glass            if 'compatible' in node.props:
2487581c01aSSimon Glass                status = node.props.get('status')
249e36024b0SSimon Glass                if (not self._include_disabled and not status or
2507581c01aSSimon Glass                        status.value != 'disabled'):
2517581c01aSSimon Glass                    self._valid_nodes.append(node)
2527581c01aSSimon Glass
2537581c01aSSimon Glass            # recurse to handle any subnodes
2542be282caSSimon Glass            self.scan_node(node)
2557581c01aSSimon Glass
2562be282caSSimon Glass    def scan_tree(self):
2577581c01aSSimon Glass        """Scan the device tree for useful information
2587581c01aSSimon Glass
2597581c01aSSimon Glass        This fills in the following properties:
2607581c01aSSimon Glass            _valid_nodes: A list of nodes we wish to consider include in the
2617581c01aSSimon Glass                platform data
2627581c01aSSimon Glass        """
2637581c01aSSimon Glass        self._valid_nodes = []
2642be282caSSimon Glass        return self.scan_node(self._fdt.GetRoot())
2657581c01aSSimon Glass
266a28bfcc3SSimon Glass    @staticmethod
267a28bfcc3SSimon Glass    def get_num_cells(node):
268a28bfcc3SSimon Glass        """Get the number of cells in addresses and sizes for this node
269a28bfcc3SSimon Glass
270a28bfcc3SSimon Glass        Args:
271a28bfcc3SSimon Glass            node: Node to check
272a28bfcc3SSimon Glass
273a28bfcc3SSimon Glass        Returns:
274a28bfcc3SSimon Glass            Tuple:
275a28bfcc3SSimon Glass                Number of address cells for this node
276a28bfcc3SSimon Glass                Number of size cells for this node
277a28bfcc3SSimon Glass        """
278a28bfcc3SSimon Glass        parent = node.parent
279a28bfcc3SSimon Glass        na, ns = 2, 2
280a28bfcc3SSimon Glass        if parent:
281a28bfcc3SSimon Glass            na_prop = parent.props.get('#address-cells')
282a28bfcc3SSimon Glass            ns_prop = parent.props.get('#size-cells')
283a28bfcc3SSimon Glass            if na_prop:
284a28bfcc3SSimon Glass                na = fdt_util.fdt32_to_cpu(na_prop.value)
285a28bfcc3SSimon Glass            if ns_prop:
286a28bfcc3SSimon Glass                ns = fdt_util.fdt32_to_cpu(ns_prop.value)
287a28bfcc3SSimon Glass        return na, ns
288a28bfcc3SSimon Glass
289a28bfcc3SSimon Glass    def scan_reg_sizes(self):
290a28bfcc3SSimon Glass        """Scan for 64-bit 'reg' properties and update the values
291a28bfcc3SSimon Glass
292a28bfcc3SSimon Glass        This finds 'reg' properties with 64-bit data and converts the value to
293a28bfcc3SSimon Glass        an array of 64-values. This allows it to be output in a way that the
294a28bfcc3SSimon Glass        C code can read.
295a28bfcc3SSimon Glass        """
296a28bfcc3SSimon Glass        for node in self._valid_nodes:
297a28bfcc3SSimon Glass            reg = node.props.get('reg')
298a28bfcc3SSimon Glass            if not reg:
299a28bfcc3SSimon Glass                continue
300a28bfcc3SSimon Glass            na, ns = self.get_num_cells(node)
301a28bfcc3SSimon Glass            total = na + ns
302a28bfcc3SSimon Glass
303a28bfcc3SSimon Glass            if reg.type != fdt.TYPE_INT:
304a28bfcc3SSimon Glass                raise ValueError("Node '%s' reg property is not an int")
305a28bfcc3SSimon Glass            if len(reg.value) % total:
306a28bfcc3SSimon Glass                raise ValueError("Node '%s' reg property has %d cells "
307a28bfcc3SSimon Glass                        'which is not a multiple of na + ns = %d + %d)' %
308a28bfcc3SSimon Glass                        (node.name, len(reg.value), na, ns))
309a28bfcc3SSimon Glass            reg.na = na
310a28bfcc3SSimon Glass            reg.ns = ns
311a28bfcc3SSimon Glass            if na != 1 or ns != 1:
312a28bfcc3SSimon Glass                reg.type = fdt.TYPE_INT64
313a28bfcc3SSimon Glass                i = 0
314a28bfcc3SSimon Glass                new_value = []
315a28bfcc3SSimon Glass                val = reg.value
316a28bfcc3SSimon Glass                if not isinstance(val, list):
317a28bfcc3SSimon Glass                    val = [val]
318a28bfcc3SSimon Glass                while i < len(val):
319a28bfcc3SSimon Glass                    addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
320a28bfcc3SSimon Glass                    i += na
321a28bfcc3SSimon Glass                    size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
322a28bfcc3SSimon Glass                    i += ns
323a28bfcc3SSimon Glass                    new_value += [addr, size]
324a28bfcc3SSimon Glass                reg.value = new_value
325a28bfcc3SSimon Glass
3262be282caSSimon Glass    def scan_structs(self):
3277581c01aSSimon Glass        """Scan the device tree building up the C structures we will use.
3287581c01aSSimon Glass
3297581c01aSSimon Glass        Build a dict keyed by C struct name containing a dict of Prop
3307581c01aSSimon Glass        object for each struct field (keyed by property name). Where the
3317581c01aSSimon Glass        same struct appears multiple times, try to use the 'widest'
3327581c01aSSimon Glass        property, i.e. the one with a type which can express all others.
3337581c01aSSimon Glass
3347581c01aSSimon Glass        Once the widest property is determined, all other properties are
3357581c01aSSimon Glass        updated to match that width.
3367581c01aSSimon Glass        """
3377581c01aSSimon Glass        structs = {}
3387581c01aSSimon Glass        for node in self._valid_nodes:
33956e0bbe0SSimon Glass            node_name, _ = get_compat_name(node)
3407581c01aSSimon Glass            fields = {}
3417581c01aSSimon Glass
3427581c01aSSimon Glass            # Get a list of all the valid properties in this node.
3437581c01aSSimon Glass            for name, prop in node.props.items():
3447581c01aSSimon Glass                if name not in PROP_IGNORE_LIST and name[0] != '#':
3457581c01aSSimon Glass                    fields[name] = copy.deepcopy(prop)
3467581c01aSSimon Glass
3477581c01aSSimon Glass            # If we've seen this node_name before, update the existing struct.
3487581c01aSSimon Glass            if node_name in structs:
3497581c01aSSimon Glass                struct = structs[node_name]
3507581c01aSSimon Glass                for name, prop in fields.items():
3517581c01aSSimon Glass                    oldprop = struct.get(name)
3527581c01aSSimon Glass                    if oldprop:
3537581c01aSSimon Glass                        oldprop.Widen(prop)
3547581c01aSSimon Glass                    else:
3557581c01aSSimon Glass                        struct[name] = prop
3567581c01aSSimon Glass
3577581c01aSSimon Glass            # Otherwise store this as a new struct.
3587581c01aSSimon Glass            else:
3597581c01aSSimon Glass                structs[node_name] = fields
3607581c01aSSimon Glass
3617581c01aSSimon Glass        upto = 0
3627581c01aSSimon Glass        for node in self._valid_nodes:
36356e0bbe0SSimon Glass            node_name, _ = get_compat_name(node)
3647581c01aSSimon Glass            struct = structs[node_name]
3657581c01aSSimon Glass            for name, prop in node.props.items():
3667581c01aSSimon Glass                if name not in PROP_IGNORE_LIST and name[0] != '#':
3677581c01aSSimon Glass                    prop.Widen(struct[name])
3687581c01aSSimon Glass            upto += 1
3697581c01aSSimon Glass
37056e0bbe0SSimon Glass            struct_name, aliases = get_compat_name(node)
3717581c01aSSimon Glass            for alias in aliases:
3727581c01aSSimon Glass                self._aliases[alias] = struct_name
3737581c01aSSimon Glass
3747581c01aSSimon Glass        return structs
3757581c01aSSimon Glass
3762be282caSSimon Glass    def scan_phandles(self):
3777581c01aSSimon Glass        """Figure out what phandles each node uses
3787581c01aSSimon Glass
3797581c01aSSimon Glass        We need to be careful when outputing nodes that use phandles since
3807581c01aSSimon Glass        they must come after the declaration of the phandles in the C file.
3817581c01aSSimon Glass        Otherwise we get a compiler error since the phandle struct is not yet
3827581c01aSSimon Glass        declared.
3837581c01aSSimon Glass
3847581c01aSSimon Glass        This function adds to each node a list of phandle nodes that the node
3857581c01aSSimon Glass        depends on. This allows us to output things in the right order.
3867581c01aSSimon Glass        """
3877581c01aSSimon Glass        for node in self._valid_nodes:
3887581c01aSSimon Glass            node.phandles = set()
3897581c01aSSimon Glass            for pname, prop in node.props.items():
3907581c01aSSimon Glass                if pname in PROP_IGNORE_LIST or pname[0] == '#':
3917581c01aSSimon Glass                    continue
392cb3f9bf4SSimon Glass                info = self.get_phandle_argc(prop, node.name)
393cb3f9bf4SSimon Glass                if info:
394cb3f9bf4SSimon Glass                    if not isinstance(prop.value, list):
395cb3f9bf4SSimon Glass                        prop.value = [prop.value]
3967581c01aSSimon Glass                    # Process the list as pairs of (phandle, id)
3972be282caSSimon Glass                    value_it = iter(prop.value)
3982be282caSSimon Glass                    for phandle_cell, _ in zip(value_it, value_it):
3997581c01aSSimon Glass                        phandle = fdt_util.fdt32_to_cpu(phandle_cell)
4000ac13c21SSimon Glass                        target_node = self._fdt.phandle_to_node[phandle]
4017581c01aSSimon Glass                        node.phandles.add(target_node)
4027581c01aSSimon Glass
4037581c01aSSimon Glass
4042be282caSSimon Glass    def generate_structs(self, structs):
4057581c01aSSimon Glass        """Generate struct defintions for the platform data
4067581c01aSSimon Glass
4077581c01aSSimon Glass        This writes out the body of a header file consisting of structure
4087581c01aSSimon Glass        definitions for node in self._valid_nodes. See the documentation in
4097581c01aSSimon Glass        README.of-plat for more information.
4107581c01aSSimon Glass        """
4112be282caSSimon Glass        self.out('#include <stdbool.h>\n')
4122be282caSSimon Glass        self.out('#include <libfdt.h>\n')
4137581c01aSSimon Glass
4147581c01aSSimon Glass        # Output the struct definition
4157581c01aSSimon Glass        for name in sorted(structs):
4162be282caSSimon Glass            self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
4177581c01aSSimon Glass            for pname in sorted(structs[name]):
4187581c01aSSimon Glass                prop = structs[name][pname]
419cb3f9bf4SSimon Glass                info = self.get_phandle_argc(prop, structs[name])
420cb3f9bf4SSimon Glass                if info:
4217581c01aSSimon Glass                    # For phandles, include a reference to the target
422*3a40acd4SSimon Glass                    struct_name = 'struct phandle_%d_arg' % info.max_args
423*3a40acd4SSimon Glass                    self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
4242be282caSSimon Glass                                             conv_name_to_c(prop.name),
4257581c01aSSimon Glass                                             len(prop.value) / 2))
4267581c01aSSimon Glass                else:
4277581c01aSSimon Glass                    ptype = TYPE_NAMES[prop.type]
4282be282caSSimon Glass                    self.out('\t%s%s' % (tab_to(2, ptype),
4292be282caSSimon Glass                                         conv_name_to_c(prop.name)))
4302be282caSSimon Glass                    if isinstance(prop.value, list):
4312be282caSSimon Glass                        self.out('[%d]' % len(prop.value))
4322be282caSSimon Glass                self.out(';\n')
4332be282caSSimon Glass            self.out('};\n')
4347581c01aSSimon Glass
4357581c01aSSimon Glass        for alias, struct_name in self._aliases.iteritems():
4362be282caSSimon Glass            self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
4377581c01aSSimon Glass                                             STRUCT_PREFIX, struct_name))
4387581c01aSSimon Glass
4392be282caSSimon Glass    def output_node(self, node):
4407581c01aSSimon Glass        """Output the C code for a node
4417581c01aSSimon Glass
4427581c01aSSimon Glass        Args:
4437581c01aSSimon Glass            node: node to output
4447581c01aSSimon Glass        """
44556e0bbe0SSimon Glass        struct_name, _ = get_compat_name(node)
4462be282caSSimon Glass        var_name = conv_name_to_c(node.name)
4472be282caSSimon Glass        self.buf('static struct %s%s %s%s = {\n' %
4487581c01aSSimon Glass                 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
4497581c01aSSimon Glass        for pname, prop in node.props.items():
4507581c01aSSimon Glass            if pname in PROP_IGNORE_LIST or pname[0] == '#':
4517581c01aSSimon Glass                continue
4522be282caSSimon Glass            member_name = conv_name_to_c(prop.name)
4532be282caSSimon Glass            self.buf('\t%s= ' % tab_to(3, '.' + member_name))
4547581c01aSSimon Glass
4557581c01aSSimon Glass            # Special handling for lists
4562be282caSSimon Glass            if isinstance(prop.value, list):
4572be282caSSimon Glass                self.buf('{')
4587581c01aSSimon Glass                vals = []
4597581c01aSSimon Glass                # For phandles, output a reference to the platform data
4607581c01aSSimon Glass                # of the target node.
461cb3f9bf4SSimon Glass                info = self.get_phandle_argc(prop, node.name)
462cb3f9bf4SSimon Glass                if info:
4637581c01aSSimon Glass                    # Process the list as pairs of (phandle, id)
4642be282caSSimon Glass                    value_it = iter(prop.value)
4652be282caSSimon Glass                    for phandle_cell, id_cell in zip(value_it, value_it):
4667581c01aSSimon Glass                        phandle = fdt_util.fdt32_to_cpu(phandle_cell)
4672be282caSSimon Glass                        id_num = fdt_util.fdt32_to_cpu(id_cell)
4680ac13c21SSimon Glass                        target_node = self._fdt.phandle_to_node[phandle]
4692be282caSSimon Glass                        name = conv_name_to_c(target_node.name)
4702be282caSSimon Glass                        vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num))
4717581c01aSSimon Glass                else:
4727581c01aSSimon Glass                    for val in prop.value:
47356e0bbe0SSimon Glass                        vals.append(get_value(prop.type, val))
47412a972efSSimon Glass
47512a972efSSimon Glass                # Put 8 values per line to avoid very long lines.
47612a972efSSimon Glass                for i in xrange(0, len(vals), 8):
47712a972efSSimon Glass                    if i:
47812a972efSSimon Glass                        self.buf(',\n\t\t')
47912a972efSSimon Glass                    self.buf(', '.join(vals[i:i + 8]))
4802be282caSSimon Glass                self.buf('}')
4817581c01aSSimon Glass            else:
48256e0bbe0SSimon Glass                self.buf(get_value(prop.type, prop.value))
4832be282caSSimon Glass            self.buf(',\n')
4842be282caSSimon Glass        self.buf('};\n')
4857581c01aSSimon Glass
4867581c01aSSimon Glass        # Add a device declaration
4872be282caSSimon Glass        self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
4882be282caSSimon Glass        self.buf('\t.name\t\t= "%s",\n' % struct_name)
4892be282caSSimon Glass        self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
4902be282caSSimon Glass        self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
4912be282caSSimon Glass        self.buf('};\n')
4922be282caSSimon Glass        self.buf('\n')
4937581c01aSSimon Glass
4942be282caSSimon Glass        self.out(''.join(self.get_buf()))
4957581c01aSSimon Glass
4962be282caSSimon Glass    def generate_tables(self):
4977581c01aSSimon Glass        """Generate device defintions for the platform data
4987581c01aSSimon Glass
4997581c01aSSimon Glass        This writes out C platform data initialisation data and
5007581c01aSSimon Glass        U_BOOT_DEVICE() declarations for each valid node. Where a node has
5017581c01aSSimon Glass        multiple compatible strings, a #define is used to make them equivalent.
5027581c01aSSimon Glass
5037581c01aSSimon Glass        See the documentation in doc/driver-model/of-plat.txt for more
5047581c01aSSimon Glass        information.
5057581c01aSSimon Glass        """
5062be282caSSimon Glass        self.out('#include <common.h>\n')
5072be282caSSimon Glass        self.out('#include <dm.h>\n')
5082be282caSSimon Glass        self.out('#include <dt-structs.h>\n')
5092be282caSSimon Glass        self.out('\n')
5107581c01aSSimon Glass        nodes_to_output = list(self._valid_nodes)
5117581c01aSSimon Glass
5127581c01aSSimon Glass        # Keep outputing nodes until there is none left
5137581c01aSSimon Glass        while nodes_to_output:
5147581c01aSSimon Glass            node = nodes_to_output[0]
5157581c01aSSimon Glass            # Output all the node's dependencies first
5167581c01aSSimon Glass            for req_node in node.phandles:
5177581c01aSSimon Glass                if req_node in nodes_to_output:
5182be282caSSimon Glass                    self.output_node(req_node)
5197581c01aSSimon Glass                    nodes_to_output.remove(req_node)
5202be282caSSimon Glass            self.output_node(node)
5217581c01aSSimon Glass            nodes_to_output.remove(node)
522fa0ea5b0SSimon Glass
523fa0ea5b0SSimon Glass
524fa0ea5b0SSimon Glassdef run_steps(args, dtb_file, include_disabled, output):
525fa0ea5b0SSimon Glass    """Run all the steps of the dtoc tool
526fa0ea5b0SSimon Glass
527fa0ea5b0SSimon Glass    Args:
528fa0ea5b0SSimon Glass        args: List of non-option arguments provided to the problem
529fa0ea5b0SSimon Glass        dtb_file: Filename of dtb file to process
530fa0ea5b0SSimon Glass        include_disabled: True to include disabled nodes
531fa0ea5b0SSimon Glass        output: Name of output file
532fa0ea5b0SSimon Glass    """
533fa0ea5b0SSimon Glass    if not args:
534fa0ea5b0SSimon Glass        raise ValueError('Please specify a command: struct, platdata')
535fa0ea5b0SSimon Glass
536fa0ea5b0SSimon Glass    plat = DtbPlatdata(dtb_file, include_disabled)
537fa0ea5b0SSimon Glass    plat.scan_dtb()
538fa0ea5b0SSimon Glass    plat.scan_tree()
539a28bfcc3SSimon Glass    plat.scan_reg_sizes()
540fa0ea5b0SSimon Glass    plat.setup_output(output)
541fa0ea5b0SSimon Glass    structs = plat.scan_structs()
542fa0ea5b0SSimon Glass    plat.scan_phandles()
543fa0ea5b0SSimon Glass
544fa0ea5b0SSimon Glass    for cmd in args[0].split(','):
545fa0ea5b0SSimon Glass        if cmd == 'struct':
546fa0ea5b0SSimon Glass            plat.generate_structs(structs)
547fa0ea5b0SSimon Glass        elif cmd == 'platdata':
548fa0ea5b0SSimon Glass            plat.generate_tables()
549fa0ea5b0SSimon Glass        else:
550fa0ea5b0SSimon Glass            raise ValueError("Unknown command '%s': (use: struct, platdata)" %
551fa0ea5b0SSimon Glass                             cmd)
552