diff options
Diffstat (limited to 'tools/dtoc/dtb_platdata.py')
| -rw-r--r-- | tools/dtoc/dtb_platdata.py | 204 | 
1 files changed, 160 insertions, 44 deletions
| diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 041a33188ff..dc9c0d9f458 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -12,6 +12,7 @@ This supports converting device tree data to C structures definitions and  static data.  """ +import collections  import copy  import sys @@ -38,11 +39,20 @@ TYPE_NAMES = {      fdt.TYPE_BYTE: 'unsigned char',      fdt.TYPE_STRING: 'const char *',      fdt.TYPE_BOOL: 'bool', +    fdt.TYPE_INT64: 'fdt64_t',  }  STRUCT_PREFIX = 'dtd_'  VAL_PREFIX = 'dtv_' +# This holds information about a property which includes phandles. +# +# max_args: integer: Maximum number or arguments that any phandle uses (int). +# args: Number of args for each phandle in the property. The total number of +#     phandles is len(args). This is a list of integers. +PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args']) + +  def conv_name_to_c(name):      """Convert a device-tree name to a C identifier @@ -95,6 +105,8 @@ def get_value(ftype, value):          return '"%s"' % value      elif ftype == fdt.TYPE_BOOL:          return 'true' +    elif ftype == fdt.TYPE_INT64: +        return '%#x' % value  def get_compat_name(node):      """Get a node's first compatible string as a C identifier @@ -113,21 +125,6 @@ def get_compat_name(node):          compat, aliases = compat[0], compat[1:]      return conv_name_to_c(compat), [conv_name_to_c(a) for a in aliases] -def is_phandle(prop): -    """Check if a node contains phandles - -    We have no reliable way of detecting whether a node uses a phandle -    or not. As an interim measure, use a list of known property names. - -    Args: -        prop: Prop object to check -    Return: -        True if the object value contains phandles, else False -    """ -    if prop.name in ['clocks']: -        return True -    return False -  class DtbPlatdata(object):      """Provide a means to convert device tree binary data to platform data @@ -141,17 +138,14 @@ class DtbPlatdata(object):          _dtb_fname: Filename of the input device tree binary file          _valid_nodes: A list of Node object with compatible strings          _include_disabled: true to include nodes marked status = "disabled" -        _phandle_nodes: A dict of nodes indexed by phandle number (1, 2...)          _outfile: The current output file (sys.stdout or a real file)          _lines: Stashed list of output lines for outputting in the future -        _phandle_nodes: A dict of Nodes indexed by phandle (an integer)      """      def __init__(self, dtb_fname, include_disabled):          self._fdt = None          self._dtb_fname = dtb_fname          self._valid_nodes = None          self._include_disabled = include_disabled -        self._phandle_nodes = {}          self._outfile = None          self._lines = []          self._aliases = {} @@ -196,6 +190,53 @@ class DtbPlatdata(object):          self._lines = []          return lines +    def out_header(self): +        """Output a message indicating that this is an auto-generated file""" +        self.out('''/* + * DO NOT MODIFY + * + * This file was generated by dtoc from a .dtb (device tree binary) file. + */ + +''') + +    def get_phandle_argc(self, prop, node_name): +        """Check if a node contains phandles + +        We have no reliable way of detecting whether a node uses a phandle +        or not. As an interim measure, use a list of known property names. + +        Args: +            prop: Prop object to check +        Return: +            Number of argument cells is this is a phandle, else None +        """ +        if prop.name in ['clocks']: +            val = prop.value +            if not isinstance(val, list): +                val = [val] +            i = 0 + +            max_args = 0 +            args = [] +            while i < len(val): +                phandle = fdt_util.fdt32_to_cpu(val[i]) +                target = self._fdt.phandle_to_node.get(phandle) +                if not target: +                    raise ValueError("Cannot parse '%s' in node '%s'" % +                                     (prop.name, node_name)) +                prop_name = '#clock-cells' +                cells = target.props.get(prop_name) +                if not cells: +                    raise ValueError("Node '%s' has no '%s' property" % +                            (target.name, prop_name)) +                num_args = fdt_util.fdt32_to_cpu(cells.value) +                max_args = max(max_args, num_args) +                args.append(num_args) +                i += 1 + num_args +            return PhandleInfo(max_args, args) +        return None +      def scan_dtb(self):          """Scan the device tree to obtain a tree of nodes and properties @@ -207,8 +248,7 @@ class DtbPlatdata(object):      def scan_node(self, root):          """Scan a node and subnodes to build a tree of node and phandle info -        This adds each node to self._valid_nodes and each phandle to -        self._phandle_nodes. +        This adds each node to self._valid_nodes.          Args:              root: Root node for scan @@ -219,10 +259,6 @@ class DtbPlatdata(object):                  if (not self._include_disabled and not status or                          status.value != 'disabled'):                      self._valid_nodes.append(node) -                    phandle_prop = node.props.get('phandle') -                    if phandle_prop: -                        phandle = phandle_prop.GetPhandle() -                        self._phandle_nodes[phandle] = node              # recurse to handle any subnodes              self.scan_node(node) @@ -231,14 +267,72 @@ class DtbPlatdata(object):          """Scan the device tree for useful information          This fills in the following properties: -            _phandle_nodes: A dict of Nodes indexed by phandle (an integer)              _valid_nodes: A list of nodes we wish to consider include in the                  platform data          """ -        self._phandle_nodes = {}          self._valid_nodes = []          return self.scan_node(self._fdt.GetRoot()) +    @staticmethod +    def get_num_cells(node): +        """Get the number of cells in addresses and sizes for this node + +        Args: +            node: Node to check + +        Returns: +            Tuple: +                Number of address cells for this node +                Number of size cells for this node +        """ +        parent = node.parent +        na, ns = 2, 2 +        if parent: +            na_prop = parent.props.get('#address-cells') +            ns_prop = parent.props.get('#size-cells') +            if na_prop: +                na = fdt_util.fdt32_to_cpu(na_prop.value) +            if ns_prop: +                ns = fdt_util.fdt32_to_cpu(ns_prop.value) +        return na, ns + +    def scan_reg_sizes(self): +        """Scan for 64-bit 'reg' properties and update the values + +        This finds 'reg' properties with 64-bit data and converts the value to +        an array of 64-values. This allows it to be output in a way that the +        C code can read. +        """ +        for node in self._valid_nodes: +            reg = node.props.get('reg') +            if not reg: +                continue +            na, ns = self.get_num_cells(node) +            total = na + ns + +            if reg.type != fdt.TYPE_INT: +                raise ValueError("Node '%s' reg property is not an int") +            if len(reg.value) % total: +                raise ValueError("Node '%s' reg property has %d cells " +                        'which is not a multiple of na + ns = %d + %d)' % +                        (node.name, len(reg.value), na, ns)) +            reg.na = na +            reg.ns = ns +            if na != 1 or ns != 1: +                reg.type = fdt.TYPE_INT64 +                i = 0 +                new_value = [] +                val = reg.value +                if not isinstance(val, list): +                    val = [val] +                while i < len(val): +                    addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.na) +                    i += na +                    size = fdt_util.fdt_cells_to_cpu(val[i:], reg.ns) +                    i += ns +                    new_value += [addr, size] +                reg.value = new_value +      def scan_structs(self):          """Scan the device tree building up the C structures we will use. @@ -305,14 +399,18 @@ class DtbPlatdata(object):              for pname, prop in node.props.items():                  if pname in PROP_IGNORE_LIST or pname[0] == '#':                      continue -                if isinstance(prop.value, list): -                    if is_phandle(prop): -                        # Process the list as pairs of (phandle, id) -                        value_it = iter(prop.value) -                        for phandle_cell, _ in zip(value_it, value_it): -                            phandle = fdt_util.fdt32_to_cpu(phandle_cell) -                            target_node = self._phandle_nodes[phandle] -                            node.phandles.add(target_node) +                info = self.get_phandle_argc(prop, node.name) +                if info: +                    if not isinstance(prop.value, list): +                        prop.value = [prop.value] +                    # Process the list as pairs of (phandle, id) +                    pos = 0 +                    for args in info.args: +                        phandle_cell = prop.value[pos] +                        phandle = fdt_util.fdt32_to_cpu(phandle_cell) +                        target_node = self._fdt.phandle_to_node[phandle] +                        node.phandles.add(target_node) +                        pos += 1 + args      def generate_structs(self, structs): @@ -322,6 +420,7 @@ class DtbPlatdata(object):          definitions for node in self._valid_nodes. See the documentation in          README.of-plat for more information.          """ +        self.out_header()          self.out('#include <stdbool.h>\n')          self.out('#include <libfdt.h>\n') @@ -330,11 +429,13 @@ class DtbPlatdata(object):              self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))              for pname in sorted(structs[name]):                  prop = structs[name][pname] -                if is_phandle(prop): +                info = self.get_phandle_argc(prop, structs[name]) +                if info:                      # For phandles, include a reference to the target -                    self.out('\t%s%s[%d]' % (tab_to(2, 'struct phandle_2_cell'), +                    struct_name = 'struct phandle_%d_arg' % info.max_args +                    self.out('\t%s%s[%d]' % (tab_to(2, struct_name),                                               conv_name_to_c(prop.name), -                                             len(prop.value) / 2)) +                                             len(info.args)))                  else:                      ptype = TYPE_NAMES[prop.type]                      self.out('\t%s%s' % (tab_to(2, ptype), @@ -370,19 +471,32 @@ class DtbPlatdata(object):                  vals = []                  # For phandles, output a reference to the platform data                  # of the target node. -                if is_phandle(prop): +                info = self.get_phandle_argc(prop, node.name) +                if info:                      # Process the list as pairs of (phandle, id) -                    value_it = iter(prop.value) -                    for phandle_cell, id_cell in zip(value_it, value_it): +                    pos = 0 +                    for args in info.args: +                        phandle_cell = prop.value[pos]                          phandle = fdt_util.fdt32_to_cpu(phandle_cell) -                        id_num = fdt_util.fdt32_to_cpu(id_cell) -                        target_node = self._phandle_nodes[phandle] +                        target_node = self._fdt.phandle_to_node[phandle]                          name = conv_name_to_c(target_node.name) -                        vals.append('{&%s%s, %d}' % (VAL_PREFIX, name, id_num)) +                        arg_values = [] +                        for i in range(args): +                            arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i]))) +                        pos += 1 + args +                        vals.append('\t{&%s%s, {%s}}' % (VAL_PREFIX, name, +                                                     ', '.join(arg_values))) +                    for val in vals: +                        self.buf('\n\t\t%s,' % val)                  else:                      for val in prop.value:                          vals.append(get_value(prop.type, val)) -                self.buf(', '.join(vals)) + +                    # Put 8 values per line to avoid very long lines. +                    for i in xrange(0, len(vals), 8): +                        if i: +                            self.buf(',\n\t\t') +                        self.buf(', '.join(vals[i:i + 8]))                  self.buf('}')              else:                  self.buf(get_value(prop.type, prop.value)) @@ -409,6 +523,7 @@ class DtbPlatdata(object):          See the documentation in doc/driver-model/of-plat.txt for more          information.          """ +        self.out_header()          self.out('#include <common.h>\n')          self.out('#include <dm.h>\n')          self.out('#include <dt-structs.h>\n') @@ -442,6 +557,7 @@ def run_steps(args, dtb_file, include_disabled, output):      plat = DtbPlatdata(dtb_file, include_disabled)      plat.scan_dtb()      plat.scan_tree() +    plat.scan_reg_sizes()      plat.setup_output(output)      structs = plat.scan_structs()      plat.scan_phandles() | 
