xref: /OK3568_Linux_fs/u-boot/tools/dtoc/dtb_platdata.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/usr/bin/python
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# Copyright (C) 2017 Google, Inc
4*4882a593Smuzhiyun# Written by Simon Glass <sjg@chromium.org>
5*4882a593Smuzhiyun#
6*4882a593Smuzhiyun# SPDX-License-Identifier:	GPL-2.0+
7*4882a593Smuzhiyun#
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun"""Device tree to platform data class
10*4882a593Smuzhiyun
11*4882a593SmuzhiyunThis supports converting device tree data to C structures definitions and
12*4882a593Smuzhiyunstatic data.
13*4882a593Smuzhiyun"""
14*4882a593Smuzhiyun
15*4882a593Smuzhiyunimport collections
16*4882a593Smuzhiyunimport copy
17*4882a593Smuzhiyunimport sys
18*4882a593Smuzhiyun
19*4882a593Smuzhiyunimport fdt
20*4882a593Smuzhiyunimport fdt_util
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun# When we see these properties we ignore them - i.e. do not create a structure member
23*4882a593SmuzhiyunPROP_IGNORE_LIST = [
24*4882a593Smuzhiyun    '#address-cells',
25*4882a593Smuzhiyun    '#gpio-cells',
26*4882a593Smuzhiyun    '#size-cells',
27*4882a593Smuzhiyun    'compatible',
28*4882a593Smuzhiyun    'linux,phandle',
29*4882a593Smuzhiyun    "status",
30*4882a593Smuzhiyun    'phandle',
31*4882a593Smuzhiyun    'u-boot,dm-pre-reloc',
32*4882a593Smuzhiyun    'u-boot,dm-tpl',
33*4882a593Smuzhiyun    'u-boot,dm-spl',
34*4882a593Smuzhiyun]
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun# C type declarations for the tyues we support
37*4882a593SmuzhiyunTYPE_NAMES = {
38*4882a593Smuzhiyun    fdt.TYPE_INT: 'fdt32_t',
39*4882a593Smuzhiyun    fdt.TYPE_BYTE: 'unsigned char',
40*4882a593Smuzhiyun    fdt.TYPE_STRING: 'const char *',
41*4882a593Smuzhiyun    fdt.TYPE_BOOL: 'bool',
42*4882a593Smuzhiyun    fdt.TYPE_INT64: 'fdt64_t',
43*4882a593Smuzhiyun}
44*4882a593Smuzhiyun
45*4882a593SmuzhiyunSTRUCT_PREFIX = 'dtd_'
46*4882a593SmuzhiyunVAL_PREFIX = 'dtv_'
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun# This holds information about a property which includes phandles.
49*4882a593Smuzhiyun#
50*4882a593Smuzhiyun# max_args: integer: Maximum number or arguments that any phandle uses (int).
51*4882a593Smuzhiyun# args: Number of args for each phandle in the property. The total number of
52*4882a593Smuzhiyun#     phandles is len(args). This is a list of integers.
53*4882a593SmuzhiyunPhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun
56*4882a593Smuzhiyundef conv_name_to_c(name):
57*4882a593Smuzhiyun    """Convert a device-tree name to a C identifier
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun    This uses multiple replace() calls instead of re.sub() since it is faster
60*4882a593Smuzhiyun    (400ms for 1m calls versus 1000ms for the 're' version).
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun    Args:
63*4882a593Smuzhiyun        name:   Name to convert
64*4882a593Smuzhiyun    Return:
65*4882a593Smuzhiyun        String containing the C version of this name
66*4882a593Smuzhiyun    """
67*4882a593Smuzhiyun    new = name.replace('@', '_at_')
68*4882a593Smuzhiyun    new = new.replace('-', '_')
69*4882a593Smuzhiyun    new = new.replace(',', '_')
70*4882a593Smuzhiyun    new = new.replace('.', '_')
71*4882a593Smuzhiyun    return new
72*4882a593Smuzhiyun
73*4882a593Smuzhiyundef tab_to(num_tabs, line):
74*4882a593Smuzhiyun    """Append tabs to a line of text to reach a tab stop.
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun    Args:
77*4882a593Smuzhiyun        num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
78*4882a593Smuzhiyun        line: Line of text to append to
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun    Returns:
81*4882a593Smuzhiyun        line with the correct number of tabs appeneded. If the line already
82*4882a593Smuzhiyun        extends past that tab stop then a single space is appended.
83*4882a593Smuzhiyun    """
84*4882a593Smuzhiyun    if len(line) >= num_tabs * 8:
85*4882a593Smuzhiyun        return line + ' '
86*4882a593Smuzhiyun    return line + '\t' * (num_tabs - len(line) // 8)
87*4882a593Smuzhiyun
88*4882a593Smuzhiyundef get_value(ftype, value):
89*4882a593Smuzhiyun    """Get a value as a C expression
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun    For integers this returns a byte-swapped (little-endian) hex string
92*4882a593Smuzhiyun    For bytes this returns a hex string, e.g. 0x12
93*4882a593Smuzhiyun    For strings this returns a literal string enclosed in quotes
94*4882a593Smuzhiyun    For booleans this return 'true'
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun    Args:
97*4882a593Smuzhiyun        type: Data type (fdt_util)
98*4882a593Smuzhiyun        value: Data value, as a string of bytes
99*4882a593Smuzhiyun    """
100*4882a593Smuzhiyun    if ftype == fdt.TYPE_INT:
101*4882a593Smuzhiyun        return '%#x' % fdt_util.fdt32_to_cpu(value)
102*4882a593Smuzhiyun    elif ftype == fdt.TYPE_BYTE:
103*4882a593Smuzhiyun        return '%#x' % ord(value[0])
104*4882a593Smuzhiyun    elif ftype == fdt.TYPE_STRING:
105*4882a593Smuzhiyun        return '"%s"' % value
106*4882a593Smuzhiyun    elif ftype == fdt.TYPE_BOOL:
107*4882a593Smuzhiyun        return 'true'
108*4882a593Smuzhiyun    elif ftype == fdt.TYPE_INT64:
109*4882a593Smuzhiyun        return '%#x' % value
110*4882a593Smuzhiyun
111*4882a593Smuzhiyundef get_compat_name(node):
112*4882a593Smuzhiyun    """Get a node's first compatible string as a C identifier
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun    Args:
115*4882a593Smuzhiyun        node: Node object to check
116*4882a593Smuzhiyun    Return:
117*4882a593Smuzhiyun        Tuple:
118*4882a593Smuzhiyun            C identifier for the first compatible string
119*4882a593Smuzhiyun            List of C identifiers for all the other compatible strings
120*4882a593Smuzhiyun                (possibly empty)
121*4882a593Smuzhiyun    """
122*4882a593Smuzhiyun    compat = node.props['compatible'].value
123*4882a593Smuzhiyun    aliases = []
124*4882a593Smuzhiyun    if isinstance(compat, list):
125*4882a593Smuzhiyun        compat, aliases = compat[0], compat[1:]
126*4882a593Smuzhiyun    return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases]
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun
129*4882a593Smuzhiyunclass DtbPlatdata(object):
130*4882a593Smuzhiyun    """Provide a means to convert device tree binary data to platform data
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun    The output of this process is C structures which can be used in space-
133*4882a593Smuzhiyun    constrained encvironments where the ~3KB code overhead of device tree
134*4882a593Smuzhiyun    code is not affordable.
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun    Properties:
137*4882a593Smuzhiyun        _fdt: Fdt object, referencing the device tree
138*4882a593Smuzhiyun        _dtb_fname: Filename of the input device tree binary file
139*4882a593Smuzhiyun        _valid_nodes: A list of Node object with compatible strings
140*4882a593Smuzhiyun        _include_disabled: true to include nodes marked status = "disabled"
141*4882a593Smuzhiyun        _outfile: The current output file (sys.stdout or a real file)
142*4882a593Smuzhiyun        _lines: Stashed list of output lines for outputting in the future
143*4882a593Smuzhiyun    """
144*4882a593Smuzhiyun    def __init__(self, dtb_fname, include_disabled):
145*4882a593Smuzhiyun        self._fdt = None
146*4882a593Smuzhiyun        self._dtb_fname = dtb_fname
147*4882a593Smuzhiyun        self._valid_nodes = None
148*4882a593Smuzhiyun        self._include_disabled = include_disabled
149*4882a593Smuzhiyun        self._outfile = None
150*4882a593Smuzhiyun        self._lines = []
151*4882a593Smuzhiyun        self._aliases = {}
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun    def setup_output(self, fname):
154*4882a593Smuzhiyun        """Set up the output destination
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun        Once this is done, future calls to self.out() will output to this
157*4882a593Smuzhiyun        file.
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun        Args:
160*4882a593Smuzhiyun            fname: Filename to send output to, or '-' for stdout
161*4882a593Smuzhiyun        """
162*4882a593Smuzhiyun        if fname == '-':
163*4882a593Smuzhiyun            self._outfile = sys.stdout
164*4882a593Smuzhiyun        else:
165*4882a593Smuzhiyun            self._outfile = open(fname, 'w')
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun    def out(self, line):
168*4882a593Smuzhiyun        """Output a string to the output file
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun        Args:
171*4882a593Smuzhiyun            line: String to output
172*4882a593Smuzhiyun        """
173*4882a593Smuzhiyun        self._outfile.write(line)
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun    def buf(self, line):
176*4882a593Smuzhiyun        """Buffer up a string to send later
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun        Args:
179*4882a593Smuzhiyun            line: String to add to our 'buffer' list
180*4882a593Smuzhiyun        """
181*4882a593Smuzhiyun        self._lines.append(line)
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun    def get_buf(self):
184*4882a593Smuzhiyun        """Get the contents of the output buffer, and clear it
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun        Returns:
187*4882a593Smuzhiyun            The output buffer, which is then cleared for future use
188*4882a593Smuzhiyun        """
189*4882a593Smuzhiyun        lines = self._lines
190*4882a593Smuzhiyun        self._lines = []
191*4882a593Smuzhiyun        return lines
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun    def out_header(self):
194*4882a593Smuzhiyun        """Output a message indicating that this is an auto-generated file"""
195*4882a593Smuzhiyun        self.out('''/*
196*4882a593Smuzhiyun * DO NOT MODIFY
197*4882a593Smuzhiyun *
198*4882a593Smuzhiyun * This file was generated by dtoc from a .dtb (device tree binary) file.
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun''')
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun    def get_phandle_argc(self, prop, node_name):
204*4882a593Smuzhiyun        """Check if a node contains phandles
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun        We have no reliable way of detecting whether a node uses a phandle
207*4882a593Smuzhiyun        or not. As an interim measure, use a list of known property names.
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun        Args:
210*4882a593Smuzhiyun            prop: Prop object to check
211*4882a593Smuzhiyun        Return:
212*4882a593Smuzhiyun            Number of argument cells is this is a phandle, else None
213*4882a593Smuzhiyun        """
214*4882a593Smuzhiyun        if prop.name in ['clocks']:
215*4882a593Smuzhiyun            val = prop.value
216*4882a593Smuzhiyun            if not isinstance(val, list):
217*4882a593Smuzhiyun                val = [val]
218*4882a593Smuzhiyun            i = 0
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun            max_args = 0
221*4882a593Smuzhiyun            args = []
222*4882a593Smuzhiyun            while i < len(val):
223*4882a593Smuzhiyun                phandle = fdt_util.fdt32_to_cpu(val[i])
224*4882a593Smuzhiyun                target = self._fdt.phandle_to_node.get(phandle)
225*4882a593Smuzhiyun                if not target:
226*4882a593Smuzhiyun                    raise ValueError("Cannot parse '%s' in node '%s'" %
227*4882a593Smuzhiyun                                     (prop.name, node_name))
228*4882a593Smuzhiyun                prop_name = '#clock-cells'
229*4882a593Smuzhiyun                cells = target.props.get(prop_name)
230*4882a593Smuzhiyun                if not cells:
231*4882a593Smuzhiyun                    raise ValueError("Node '%s' has no '%s' property" %
232*4882a593Smuzhiyun                            (target.name, prop_name))
233*4882a593Smuzhiyun                num_args = fdt_util.fdt32_to_cpu(cells.value)
234*4882a593Smuzhiyun                max_args = max(max_args, num_args)
235*4882a593Smuzhiyun                args.append(num_args)
236*4882a593Smuzhiyun                i += 1 + num_args
237*4882a593Smuzhiyun            return PhandleInfo(max_args, args)
238*4882a593Smuzhiyun        return None
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun    def scan_dtb(self):
241*4882a593Smuzhiyun        """Scan the device tree to obtain a tree of nodes and properties
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun        Once this is done, self._fdt.GetRoot() can be called to obtain the
244*4882a593Smuzhiyun        device tree root node, and progress from there.
245*4882a593Smuzhiyun        """
246*4882a593Smuzhiyun        self._fdt = fdt.FdtScan(self._dtb_fname)
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun    def scan_node(self, root):
249*4882a593Smuzhiyun        """Scan a node and subnodes to build a tree of node and phandle info
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun        This adds each node to self._valid_nodes.
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun        Args:
254*4882a593Smuzhiyun            root: Root node for scan
255*4882a593Smuzhiyun        """
256*4882a593Smuzhiyun        for node in root.subnodes:
257*4882a593Smuzhiyun            if 'compatible' in node.props:
258*4882a593Smuzhiyun                status = node.props.get('status')
259*4882a593Smuzhiyun                if (not self._include_disabled and not status or
260*4882a593Smuzhiyun                        status.value != 'disabled'):
261*4882a593Smuzhiyun                    self._valid_nodes.append(node)
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun            # recurse to handle any subnodes
264*4882a593Smuzhiyun            self.scan_node(node)
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun    def scan_tree(self):
267*4882a593Smuzhiyun        """Scan the device tree for useful information
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun        This fills in the following properties:
270*4882a593Smuzhiyun            _valid_nodes: A list of nodes we wish to consider include in the
271*4882a593Smuzhiyun                platform data
272*4882a593Smuzhiyun        """
273*4882a593Smuzhiyun        self._valid_nodes = []
274*4882a593Smuzhiyun        return self.scan_node(self._fdt.GetRoot())
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun    @staticmethod
277*4882a593Smuzhiyun    def get_num_cells(node):
278*4882a593Smuzhiyun        """Get the number of cells in addresses and sizes for this node
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun        Args:
281*4882a593Smuzhiyun            node: Node to check
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun        Returns:
284*4882a593Smuzhiyun            Tuple:
285*4882a593Smuzhiyun                Number of address cells for this node
286*4882a593Smuzhiyun                Number of size cells for this node
287*4882a593Smuzhiyun        """
288*4882a593Smuzhiyun        parent = node.parent
289*4882a593Smuzhiyun        na, ns = 2, 2
290*4882a593Smuzhiyun        if parent:
291*4882a593Smuzhiyun            na_prop = parent.props.get('#address-cells')
292*4882a593Smuzhiyun            ns_prop = parent.props.get('#size-cells')
293*4882a593Smuzhiyun            if na_prop:
294*4882a593Smuzhiyun                na = fdt_util.fdt32_to_cpu(na_prop.value)
295*4882a593Smuzhiyun            if ns_prop:
296*4882a593Smuzhiyun                ns = fdt_util.fdt32_to_cpu(ns_prop.value)
297*4882a593Smuzhiyun        return na, ns
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun    def scan_reg_sizes(self):
300*4882a593Smuzhiyun        """Scan for 64-bit 'reg' properties and update the values
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun        This finds 'reg' properties with 64-bit data and converts the value to
303*4882a593Smuzhiyun        an array of 64-values. This allows it to be output in a way that the
304*4882a593Smuzhiyun        C code can read.
305*4882a593Smuzhiyun        """
306*4882a593Smuzhiyun        for node in self._valid_nodes:
307*4882a593Smuzhiyun            reg = node.props.get('reg')
308*4882a593Smuzhiyun            if not reg:
309*4882a593Smuzhiyun                continue
310*4882a593Smuzhiyun            na, ns = self.get_num_cells(node)
311*4882a593Smuzhiyun            total = na + ns
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun            if reg.type != fdt.TYPE_INT:
314*4882a593Smuzhiyun                raise ValueError("Node '%s' reg property is not an int")
315*4882a593Smuzhiyun            if len(reg.value) % total:
316*4882a593Smuzhiyun                raise ValueError("Node '%s' reg property has %d cells "
317*4882a593Smuzhiyun                        'which is not a multiple of na + ns = %d + %d)' %
318*4882a593Smuzhiyun                        (node.name, len(reg.value), na, ns))
319*4882a593Smuzhiyun            reg.na = na
320*4882a593Smuzhiyun            reg.ns = ns
321*4882a593Smuzhiyun            if na != 1 or ns != 1:
322*4882a593Smuzhiyun                reg.type = fdt.TYPE_INT64
323*4882a593Smuzhiyun                i = 0
324*4882a593Smuzhiyun                new_value = []
325*4882a593Smuzhiyun                val = reg.value
326*4882a593Smuzhiyun                if not isinstance(val, list):
327*4882a593Smuzhiyun                    val = [val]
328*4882a593Smuzhiyun                while i < len(val):
329*4882a593Smuzhiyun                    addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na)
330*4882a593Smuzhiyun                    i += na
331*4882a593Smuzhiyun                    size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns)
332*4882a593Smuzhiyun                    i += ns
333*4882a593Smuzhiyun                    new_value += [addr, size]
334*4882a593Smuzhiyun                reg.value = new_value
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun    def scan_structs(self):
337*4882a593Smuzhiyun        """Scan the device tree building up the C structures we will use.
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun        Build a dict keyed by C struct name containing a dict of Prop
340*4882a593Smuzhiyun        object for each struct field (keyed by property name). Where the
341*4882a593Smuzhiyun        same struct appears multiple times, try to use the 'widest'
342*4882a593Smuzhiyun        property, i.e. the one with a type which can express all others.
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun        Once the widest property is determined, all other properties are
345*4882a593Smuzhiyun        updated to match that width.
346*4882a593Smuzhiyun        """
347*4882a593Smuzhiyun        structs = {}
348*4882a593Smuzhiyun        for node in self._valid_nodes:
349*4882a593Smuzhiyun            node_name, _ = get_compat_name(node)
350*4882a593Smuzhiyun            fields = {}
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun            # Get a list of all the valid properties in this node.
353*4882a593Smuzhiyun            for name, prop in node.props.items():
354*4882a593Smuzhiyun                if name not in PROP_IGNORE_LIST and name[0] != '#':
355*4882a593Smuzhiyun                    fields[name] = copy.deepcopy(prop)
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun            # If we've seen this node_name before, update the existing struct.
358*4882a593Smuzhiyun            if node_name in structs:
359*4882a593Smuzhiyun                struct = structs[node_name]
360*4882a593Smuzhiyun                for name, prop in fields.items():
361*4882a593Smuzhiyun                    oldprop = struct.get(name)
362*4882a593Smuzhiyun                    if oldprop:
363*4882a593Smuzhiyun                        oldprop.Widen(prop)
364*4882a593Smuzhiyun                    else:
365*4882a593Smuzhiyun                        struct[name] = prop
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun            # Otherwise store this as a new struct.
368*4882a593Smuzhiyun            else:
369*4882a593Smuzhiyun                structs[node_name] = fields
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun        upto = 0
372*4882a593Smuzhiyun        for node in self._valid_nodes:
373*4882a593Smuzhiyun            node_name, _ = get_compat_name(node)
374*4882a593Smuzhiyun            struct = structs[node_name]
375*4882a593Smuzhiyun            for name, prop in node.props.items():
376*4882a593Smuzhiyun                if name not in PROP_IGNORE_LIST and name[0] != '#':
377*4882a593Smuzhiyun                    prop.Widen(struct[name])
378*4882a593Smuzhiyun            upto += 1
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun            struct_name, aliases = get_compat_name(node)
381*4882a593Smuzhiyun            for alias in aliases:
382*4882a593Smuzhiyun                self._aliases[alias] = struct_name
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun        return structs
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun    def scan_phandles(self):
387*4882a593Smuzhiyun        """Figure out what phandles each node uses
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun        We need to be careful when outputing nodes that use phandles since
390*4882a593Smuzhiyun        they must come after the declaration of the phandles in the C file.
391*4882a593Smuzhiyun        Otherwise we get a compiler error since the phandle struct is not yet
392*4882a593Smuzhiyun        declared.
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun        This function adds to each node a list of phandle nodes that the node
395*4882a593Smuzhiyun        depends on. This allows us to output things in the right order.
396*4882a593Smuzhiyun        """
397*4882a593Smuzhiyun        for node in self._valid_nodes:
398*4882a593Smuzhiyun            node.phandles = set()
399*4882a593Smuzhiyun            for pname, prop in node.props.items():
400*4882a593Smuzhiyun                if pname in PROP_IGNORE_LIST or pname[0] == '#':
401*4882a593Smuzhiyun                    continue
402*4882a593Smuzhiyun                info = self.get_phandle_argc(prop, node.name)
403*4882a593Smuzhiyun                if info:
404*4882a593Smuzhiyun                    if not isinstance(prop.value, list):
405*4882a593Smuzhiyun                        prop.value = [prop.value]
406*4882a593Smuzhiyun                    # Process the list as pairs of (phandle, id)
407*4882a593Smuzhiyun                    pos = 0
408*4882a593Smuzhiyun                    for args in info.args:
409*4882a593Smuzhiyun                        phandle_cell = prop.value[pos]
410*4882a593Smuzhiyun                        phandle = fdt_util.fdt32_to_cpu(phandle_cell)
411*4882a593Smuzhiyun                        target_node = self._fdt.phandle_to_node[phandle]
412*4882a593Smuzhiyun                        node.phandles.add(target_node)
413*4882a593Smuzhiyun                        pos += 1 + args
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun    def generate_structs(self, structs):
417*4882a593Smuzhiyun        """Generate struct defintions for the platform data
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun        This writes out the body of a header file consisting of structure
420*4882a593Smuzhiyun        definitions for node in self._valid_nodes. See the documentation in
421*4882a593Smuzhiyun        README.of-plat for more information.
422*4882a593Smuzhiyun        """
423*4882a593Smuzhiyun        self.out_header()
424*4882a593Smuzhiyun        self.out('#include <stdbool.h>\n')
425*4882a593Smuzhiyun        self.out('#include <linux/libfdt.h>\n')
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun        # Output the struct definition
428*4882a593Smuzhiyun        for name in sorted(structs):
429*4882a593Smuzhiyun            self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
430*4882a593Smuzhiyun            for pname in sorted(structs[name]):
431*4882a593Smuzhiyun                prop = structs[name][pname]
432*4882a593Smuzhiyun                info = self.get_phandle_argc(prop, structs[name])
433*4882a593Smuzhiyun                if info:
434*4882a593Smuzhiyun                    # For phandles, include a reference to the target
435*4882a593Smuzhiyun                    struct_name = 'struct phandle_%d_arg' % info.max_args
436*4882a593Smuzhiyun                    self.out('\t%s%s[%d]' % (tab_to(2, struct_name),
437*4882a593Smuzhiyun                                             conv_name_to_c(prop.name),
438*4882a593Smuzhiyun                                             len(info.args)))
439*4882a593Smuzhiyun                else:
440*4882a593Smuzhiyun                    ptype = TYPE_NAMES[prop.type]
441*4882a593Smuzhiyun                    self.out('\t%s%s' % (tab_to(2, ptype),
442*4882a593Smuzhiyun                                         conv_name_to_c(prop.name)))
443*4882a593Smuzhiyun                    if isinstance(prop.value, list):
444*4882a593Smuzhiyun                        self.out('[%d]' % len(prop.value))
445*4882a593Smuzhiyun                self.out(';\n')
446*4882a593Smuzhiyun            self.out('};\n')
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun        for alias, struct_name in self._aliases.iteritems():
449*4882a593Smuzhiyun            self.out('#define %s%s %s%s\n'% (STRUCT_PREFIX, alias,
450*4882a593Smuzhiyun                                             STRUCT_PREFIX, struct_name))
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun    def output_node(self, node):
453*4882a593Smuzhiyun        """Output the C code for a node
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun        Args:
456*4882a593Smuzhiyun            node: node to output
457*4882a593Smuzhiyun        """
458*4882a593Smuzhiyun        struct_name, _ = get_compat_name(node)
459*4882a593Smuzhiyun        var_name = conv_name_to_c(node.name)
460*4882a593Smuzhiyun        self.buf('static struct %s%s %s%s = {\n' %
461*4882a593Smuzhiyun                 (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
462*4882a593Smuzhiyun        for pname, prop in node.props.items():
463*4882a593Smuzhiyun            if pname in PROP_IGNORE_LIST or pname[0] == '#':
464*4882a593Smuzhiyun                continue
465*4882a593Smuzhiyun            member_name = conv_name_to_c(prop.name)
466*4882a593Smuzhiyun            self.buf('\t%s= ' % tab_to(3, '.' + member_name))
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun            # Special handling for lists
469*4882a593Smuzhiyun            if isinstance(prop.value, list):
470*4882a593Smuzhiyun                self.buf('{')
471*4882a593Smuzhiyun                vals = []
472*4882a593Smuzhiyun                # For phandles, output a reference to the platform data
473*4882a593Smuzhiyun                # of the target node.
474*4882a593Smuzhiyun                info = self.get_phandle_argc(prop, node.name)
475*4882a593Smuzhiyun                if info:
476*4882a593Smuzhiyun                    # Process the list as pairs of (phandle, id)
477*4882a593Smuzhiyun                    pos = 0
478*4882a593Smuzhiyun                    for args in info.args:
479*4882a593Smuzhiyun                        phandle_cell = prop.value[pos]
480*4882a593Smuzhiyun                        phandle = fdt_util.fdt32_to_cpu(phandle_cell)
481*4882a593Smuzhiyun                        target_node = self._fdt.phandle_to_node[phandle]
482*4882a593Smuzhiyun                        name = conv_name_to_c(target_node.name)
483*4882a593Smuzhiyun                        arg_values = []
484*4882a593Smuzhiyun                        for i in range(args):
485*4882a593Smuzhiyun                            arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
486*4882a593Smuzhiyun                        pos += 1 + args
487*4882a593Smuzhiyun                        vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name,
488*4882a593Smuzhiyun                                                     ', '.join(arg_values)))
489*4882a593Smuzhiyun                    for val in vals:
490*4882a593Smuzhiyun                        self.buf('\n\t\t%s,' % val)
491*4882a593Smuzhiyun                else:
492*4882a593Smuzhiyun                    for val in prop.value:
493*4882a593Smuzhiyun                        vals.append(get_value(prop.type, val))
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun                    # Put 8 values per line to avoid very long lines.
496*4882a593Smuzhiyun                    for i in xrange(0, len(vals), 8):
497*4882a593Smuzhiyun                        if i:
498*4882a593Smuzhiyun                            self.buf(',\n\t\t')
499*4882a593Smuzhiyun                        self.buf(', '.join(vals[i:i + 8]))
500*4882a593Smuzhiyun                self.buf('}')
501*4882a593Smuzhiyun            else:
502*4882a593Smuzhiyun                self.buf(get_value(prop.type, prop.value))
503*4882a593Smuzhiyun            self.buf(',\n')
504*4882a593Smuzhiyun        self.buf('};\n')
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun        # Add a device declaration
507*4882a593Smuzhiyun        self.buf('U_BOOT_DEVICE(%s) = {\n' % var_name)
508*4882a593Smuzhiyun        self.buf('\t.name\t\t= "%s",\n' % struct_name)
509*4882a593Smuzhiyun        self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
510*4882a593Smuzhiyun        self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
511*4882a593Smuzhiyun        self.buf('};\n')
512*4882a593Smuzhiyun        self.buf('\n')
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun        self.out(''.join(self.get_buf()))
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun    def generate_tables(self):
517*4882a593Smuzhiyun        """Generate device defintions for the platform data
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun        This writes out C platform data initialisation data and
520*4882a593Smuzhiyun        U_BOOT_DEVICE() declarations for each valid node. Where a node has
521*4882a593Smuzhiyun        multiple compatible strings, a #define is used to make them equivalent.
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun        See the documentation in doc/driver-model/of-plat.txt for more
524*4882a593Smuzhiyun        information.
525*4882a593Smuzhiyun        """
526*4882a593Smuzhiyun        self.out_header()
527*4882a593Smuzhiyun        self.out('#include <common.h>\n')
528*4882a593Smuzhiyun        self.out('#include <dm.h>\n')
529*4882a593Smuzhiyun        self.out('#include <dt-structs.h>\n')
530*4882a593Smuzhiyun        self.out('\n')
531*4882a593Smuzhiyun        nodes_to_output = list(self._valid_nodes)
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun        # Keep outputing nodes until there is none left
534*4882a593Smuzhiyun        while nodes_to_output:
535*4882a593Smuzhiyun            node = nodes_to_output[0]
536*4882a593Smuzhiyun            # Output all the node's dependencies first
537*4882a593Smuzhiyun            for req_node in node.phandles:
538*4882a593Smuzhiyun                if req_node in nodes_to_output:
539*4882a593Smuzhiyun                    self.output_node(req_node)
540*4882a593Smuzhiyun                    nodes_to_output.remove(req_node)
541*4882a593Smuzhiyun            self.output_node(node)
542*4882a593Smuzhiyun            nodes_to_output.remove(node)
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun
545*4882a593Smuzhiyundef run_steps(args, dtb_file, include_disabled, output):
546*4882a593Smuzhiyun    """Run all the steps of the dtoc tool
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun    Args:
549*4882a593Smuzhiyun        args: List of non-option arguments provided to the problem
550*4882a593Smuzhiyun        dtb_file: Filename of dtb file to process
551*4882a593Smuzhiyun        include_disabled: True to include disabled nodes
552*4882a593Smuzhiyun        output: Name of output file
553*4882a593Smuzhiyun    """
554*4882a593Smuzhiyun    if not args:
555*4882a593Smuzhiyun        raise ValueError('Please specify a command: struct, platdata')
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun    plat = DtbPlatdata(dtb_file, include_disabled)
558*4882a593Smuzhiyun    plat.scan_dtb()
559*4882a593Smuzhiyun    plat.scan_tree()
560*4882a593Smuzhiyun    plat.scan_reg_sizes()
561*4882a593Smuzhiyun    plat.setup_output(output)
562*4882a593Smuzhiyun    structs = plat.scan_structs()
563*4882a593Smuzhiyun    plat.scan_phandles()
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun    for cmd in args[0].split(','):
566*4882a593Smuzhiyun        if cmd == 'struct':
567*4882a593Smuzhiyun            plat.generate_structs(structs)
568*4882a593Smuzhiyun        elif cmd == 'platdata':
569*4882a593Smuzhiyun            plat.generate_tables()
570*4882a593Smuzhiyun        else:
571*4882a593Smuzhiyun            raise ValueError("Unknown command '%s': (use: struct, platdata)" %
572*4882a593Smuzhiyun                             cmd)
573