]> Git Repo - u-boot.git/blobdiff - tools/dtoc/dtb_platdata.py
dtoc: Tidy up more Python style in dtb_platdata
[u-boot.git] / tools / dtoc / dtb_platdata.py
index bd1daa4379aed1bed0356205a3ea11f87ccaaa96..b0d3c27720c681289caa5fb564f6023dc4bf9c96 100644 (file)
@@ -9,6 +9,8 @@
 
 This supports converting device tree data to C structures definitions and
 static data.
+
+See doc/driver-model/of-plat.rst for more informaiton
 """
 
 import collections
@@ -19,9 +21,9 @@ import sys
 
 from dtoc import fdt
 from dtoc import fdt_util
-from patman import tools
 
-# When we see these properties we ignore them - i.e. do not create a structure member
+# When we see these properties we ignore them - i.e. do not create a structure
+# member
 PROP_IGNORE_LIST = [
     '#address-cells',
     '#gpio-cells',
@@ -35,13 +37,13 @@ PROP_IGNORE_LIST = [
     'u-boot,dm-spl',
 ]
 
-# C type declarations for the tyues we support
+# C type declarations for the types we support
 TYPE_NAMES = {
-    fdt.TYPE_INT: 'fdt32_t',
-    fdt.TYPE_BYTE: 'unsigned char',
-    fdt.TYPE_STRING: 'const char *',
-    fdt.TYPE_BOOL: 'bool',
-    fdt.TYPE_INT64: 'fdt64_t',
+    fdt.Type.INT: 'fdt32_t',
+    fdt.Type.BYTE: 'unsigned char',
+    fdt.Type.STRING: 'const char *',
+    fdt.Type.BOOL: 'bool',
+    fdt.Type.INT64: 'fdt64_t',
 }
 
 STRUCT_PREFIX = 'dtd_'
@@ -54,6 +56,13 @@ VAL_PREFIX = 'dtv_'
 #     phandles is len(args). This is a list of integers.
 PhandleInfo = collections.namedtuple('PhandleInfo', ['max_args', 'args'])
 
+# Holds a single phandle link, allowing a C struct value to be assigned to point
+# to a device
+#
+# var_node: C variable to assign (e.g. 'dtv_mmc.clocks[0].node')
+# dev_name: Name of device to assign to (e.g. 'clock')
+PhandleLink = collections.namedtuple('PhandleLink', ['var_node', 'dev_name'])
+
 
 def conv_name_to_c(name):
     """Convert a device-tree name to a C identifier
@@ -62,9 +71,9 @@ def conv_name_to_c(name):
     (400ms for 1m calls versus 1000ms for the 're' version).
 
     Args:
-        name:   Name to convert
+        name (str): Name to convert
     Return:
-        String containing the C version of this name
+        str: String containing the C version of this name
     """
     new = name.replace('@', '_at_')
     new = new.replace('-', '_')
@@ -76,11 +85,11 @@ def tab_to(num_tabs, line):
     """Append tabs to a line of text to reach a tab stop.
 
     Args:
-        num_tabs: Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
-        line: Line of text to append to
+        num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
+        line (str): Line of text to append to
 
     Returns:
-        line with the correct number of tabs appeneded. If the line already
+        str: line with the correct number of tabs appeneded. If the line already
         extends past that tab stop then a single space is appended.
     """
     if len(line) >= num_tabs * 8:
@@ -96,27 +105,31 @@ def get_value(ftype, value):
     For booleans this return 'true'
 
     Args:
-        type: Data type (fdt_util)
-        value: Data value, as a string of bytes
+        ftype (fdt.Type): Data type (fdt_util)
+        value (bytes): Data value, as a string of bytes
+
+    Returns:
+        str: String representation of the value
     """
-    if ftype == fdt.TYPE_INT:
+    if ftype == fdt.Type.INT:
         return '%#x' % fdt_util.fdt32_to_cpu(value)
-    elif ftype == fdt.TYPE_BYTE:
-        return '%#x' % tools.ToByte(value[0])
-    elif ftype == fdt.TYPE_STRING:
+    elif ftype == fdt.Type.BYTE:
+        char = value[0]
+        return '%#x' % (ord(char) if isinstance(char, str) else char)
+    elif ftype == fdt.Type.STRING:
         # Handle evil ACPI backslashes by adding another backslash before them.
         # So "\\_SB.GPO0" in the device tree effectively stays like that in C
         return '"%s"' % value.replace('\\', '\\\\')
-    elif ftype == fdt.TYPE_BOOL:
+    elif ftype == fdt.Type.BOOL:
         return 'true'
-    elif ftype == fdt.TYPE_INT64:
+    else:  # ftype == fdt.Type.INT64:
         return '%#x' % value
 
 def get_compat_name(node):
     """Get the node's list of compatible string as a C identifiers
 
     Args:
-        node: Node object to check
+        node (fdt.Node): Node object to check
     Return:
         List of C identifiers for all the compatible strings
     """
@@ -136,7 +149,8 @@ class DtbPlatdata(object):
     Properties:
         _fdt: Fdt object, referencing the device tree
         _dtb_fname: Filename of the input device tree binary file
-        _valid_nodes: A list of Node object with compatible strings
+        _valid_nodes: A list of Node object with compatible strings. The list
+            is ordered by conv_name_to_c(node.name)
         _include_disabled: true to include nodes marked status = "disabled"
         _outfile: The current output file (sys.stdout or a real file)
         _warning_disabled: true to disable warnings about driver names not found
@@ -146,11 +160,10 @@ class DtbPlatdata(object):
             key: Driver alias declared with
                 U_BOOT_DRIVER_ALIAS(driver_alias, driver_name)
             value: Driver name declared with U_BOOT_DRIVER(driver_name)
-        _links: List of links to be included in dm_populate_phandle_data()
         _drivers_additional: List of additional drivers to use during scanning
     """
     def __init__(self, dtb_fname, include_disabled, warning_disabled,
-                 drivers_additional=[]):
+                 drivers_additional=None):
         self._fdt = None
         self._dtb_fname = dtb_fname
         self._valid_nodes = None
@@ -160,8 +173,7 @@ class DtbPlatdata(object):
         self._lines = []
         self._drivers = []
         self._driver_aliases = {}
-        self._links = []
-        self._drivers_additional = drivers_additional
+        self._drivers_additional = drivers_additional or []
 
     def get_normalized_compat_name(self, node):
         """Get a node's normalized compat name
@@ -206,7 +218,7 @@ class DtbPlatdata(object):
         file.
 
         Args:
-            fname: Filename to send output to, or '-' for stdout
+            fname (str): Filename to send output to, or '-' for stdout
         """
         if fname == '-':
             self._outfile = sys.stdout
@@ -217,7 +229,7 @@ class DtbPlatdata(object):
         """Output a string to the output file
 
         Args:
-            line: String to output
+            line (str): String to output
         """
         self._outfile.write(line)
 
@@ -225,7 +237,7 @@ class DtbPlatdata(object):
         """Buffer up a string to send later
 
         Args:
-            line: String to add to our 'buffer' list
+            line (str): String to add to our 'buffer' list
         """
         self._lines.append(line)
 
@@ -233,7 +245,7 @@ class DtbPlatdata(object):
         """Get the contents of the output buffer, and clear it
 
         Returns:
-            The output buffer, which is then cleared for future use
+            list(str): The output buffer, which is then cleared for future use
         """
         lines = self._lines
         self._lines = []
@@ -256,9 +268,14 @@ class DtbPlatdata(object):
         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
+            prop (fdt.Prop): Prop object to check
+            node_name (str): Node name, only used for raising an error
+        Returns:
+            int or None: Number of argument cells is this is a phandle,
+                else None
+        Raises:
+            ValueError: if the phandle cannot be parsed or the required property
+                is not present
         """
         if prop.name in ['clocks', 'cd-gpios']:
             if not isinstance(prop.value, list):
@@ -287,7 +304,7 @@ class DtbPlatdata(object):
                         break
                 if not cells:
                     raise ValueError("Node '%s' has no cells property" %
-                            (target.name))
+                                     (target.name))
                 num_args = fdt_util.fdt32_to_cpu(cells.value)
                 max_args = max(max_args, num_args)
                 args.append(num_args)
@@ -295,20 +312,20 @@ class DtbPlatdata(object):
             return PhandleInfo(max_args, args)
         return None
 
-    def scan_driver(self, fn):
+    def scan_driver(self, fname):
         """Scan a driver file to build a list of driver names and aliases
 
         This procedure will populate self._drivers and self._driver_aliases
 
         Args
-            fn: Driver filename to scan
+            fname: Driver filename to scan
         """
-        with open(fn, encoding='utf-8') as fd:
+        with open(fname, encoding='utf-8') as inf:
             try:
-                buff = fd.read()
+                buff = inf.read()
             except UnicodeDecodeError:
                 # This seems to happen on older Python versions
-                print("Skipping file '%s' due to unicode error" % fn)
+                print("Skipping file '%s' due to unicode error" % fname)
                 return
 
             # The following re will search for driver names declared as
@@ -320,8 +337,9 @@ class DtbPlatdata(object):
 
             # The following re will search for driver aliases declared as
             # U_BOOT_DRIVER_ALIAS(alias, driver_name)
-            driver_aliases = re.findall('U_BOOT_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
-                                        buff)
+            driver_aliases = re.findall(
+                'U_BOOT_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
+                buff)
 
             for alias in driver_aliases: # pragma: no cover
                 if len(alias) != 2:
@@ -337,19 +355,19 @@ class DtbPlatdata(object):
         basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
         if basedir == '':
             basedir = './'
-        for (dirpath, dirnames, filenames) in os.walk(basedir):
-            for fn in filenames:
-                if not fn.endswith('.c'):
+        for (dirpath, _, filenames) in os.walk(basedir):
+            for fname in filenames:
+                if not fname.endswith('.c'):
                     continue
-                self.scan_driver(dirpath + '/' + fn)
+                self.scan_driver(dirpath + '/' + fname)
 
-        for fn in self._drivers_additional:
-            if not isinstance(fn, str) or len(fn) == 0:
+        for fname in self._drivers_additional:
+            if not isinstance(fname, str) or len(fname) == 0:
                 continue
-            if fn[0] == '/':
-                self.scan_driver(fn)
+            if fname[0] == '/':
+                self.scan_driver(fname)
             else:
-                self.scan_driver(basedir + '/' + fn)
+                self.scan_driver(basedir + '/' + fname)
 
     def scan_dtb(self):
         """Scan the device tree to obtain a tree of nodes and properties
@@ -359,23 +377,24 @@ class DtbPlatdata(object):
         """
         self._fdt = fdt.FdtScan(self._dtb_fname)
 
-    def scan_node(self, root):
+    def scan_node(self, root, valid_nodes):
         """Scan a node and subnodes to build a tree of node and phandle info
 
         This adds each node to self._valid_nodes.
 
         Args:
             root: Root node for scan
+            valid_nodes: List of Node objects to add to
         """
         for node in root.subnodes:
             if 'compatible' in node.props:
                 status = node.props.get('status')
                 if (not self._include_disabled and not status or
                         status.value != 'disabled'):
-                    self._valid_nodes.append(node)
+                    valid_nodes.append(node)
 
             # recurse to handle any subnodes
-            self.scan_node(node)
+            self.scan_node(node, valid_nodes)
 
     def scan_tree(self):
         """Scan the device tree for useful information
@@ -384,15 +403,19 @@ class DtbPlatdata(object):
             _valid_nodes: A list of nodes we wish to consider include in the
                 platform data
         """
-        self._valid_nodes = []
-        return self.scan_node(self._fdt.GetRoot())
+        valid_nodes = []
+        self.scan_node(self._fdt.GetRoot(), valid_nodes)
+        self._valid_nodes = sorted(valid_nodes,
+                                   key=lambda x: conv_name_to_c(x.name))
+        for idx, node in enumerate(self._valid_nodes):
+            node.idx = idx
 
     @staticmethod
     def get_num_cells(node):
         """Get the number of cells in addresses and sizes for this node
 
         Args:
-            node: Node to check
+            node (fdt.None): Node to check
 
         Returns:
             Tuple:
@@ -400,15 +423,15 @@ class DtbPlatdata(object):
                 Number of size cells for this node
         """
         parent = node.parent
-        na, ns = 2, 2
+        num_addr, num_size = 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
+            addr_prop = parent.props.get('#address-cells')
+            size_prop = parent.props.get('#size-cells')
+            if addr_prop:
+                num_addr = fdt_util.fdt32_to_cpu(addr_prop.value)
+            if size_prop:
+                num_size = fdt_util.fdt32_to_cpu(size_prop.value)
+        return num_addr, num_size
 
     def scan_reg_sizes(self):
         """Scan for 64-bit 'reg' properties and update the values
@@ -421,30 +444,31 @@ class DtbPlatdata(object):
             reg = node.props.get('reg')
             if not reg:
                 continue
-            na, ns = self.get_num_cells(node)
-            total = na + ns
+            num_addr, num_size = self.get_num_cells(node)
+            total = num_addr + num_size
 
-            if reg.type != fdt.TYPE_INT:
+            if reg.type != fdt.Type.INT:
                 raise ValueError("Node '%s' reg property is not an int" %
                                  node.name)
             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
+                raise ValueError(
+                    "Node '%s' reg property has %d cells "
+                    'which is not a multiple of na + ns = %d + %d)' %
+                    (node.name, len(reg.value), num_addr, num_size))
+            reg.num_addr = num_addr
+            reg.num_size = num_size
+            if num_addr != 1 or num_size != 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
+                    addr = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_addr)
+                    i += num_addr
+                    size = fdt_util.fdt_cells_to_cpu(val[i:], reg.num_size)
+                    i += num_size
                     new_value += [addr, size]
                 reg.value = new_value
 
@@ -458,8 +482,15 @@ class DtbPlatdata(object):
 
         Once the widest property is determined, all other properties are
         updated to match that width.
+
+        Returns:
+            dict containing structures:
+                key (str): Node name, as a C identifier
+                value: dict containing structure fields:
+                    key (str): Field name
+                    value: Prop object with field information
         """
-        structs = {}
+        structs = collections.OrderedDict()
         for node in self._valid_nodes:
             node_name, _ = self.get_normalized_compat_name(node)
             fields = {}
@@ -483,14 +514,12 @@ class DtbPlatdata(object):
             else:
                 structs[node_name] = fields
 
-        upto = 0
         for node in self._valid_nodes:
             node_name, _ = self.get_normalized_compat_name(node)
             struct = structs[node_name]
             for name, prop in node.props.items():
                 if name not in PROP_IGNORE_LIST and name[0] != '#':
                     prop.Widen(struct[name])
-            upto += 1
 
         return structs
 
@@ -528,6 +557,14 @@ class DtbPlatdata(object):
         This writes out the body of a header file consisting of structure
         definitions for node in self._valid_nodes. See the documentation in
         doc/driver-model/of-plat.rst for more information.
+
+        Args:
+            structs: dict containing structures:
+                key (str): Node name, as a C identifier
+                value: dict containing structure fields:
+                    key (str): Field name
+                    value: Prop object with field information
+
         """
         self.out_header()
         self.out('#include <stdbool.h>\n')
@@ -558,7 +595,7 @@ class DtbPlatdata(object):
         """Output the C code for a node
 
         Args:
-            node: node to output
+            node (fdt.Node): node to output
         """
         def _output_list(node, prop):
             """Output the C code for a devicetree property that holds a list
@@ -575,26 +612,17 @@ class DtbPlatdata(object):
             if info:
                 # Process the list as pairs of (phandle, id)
                 pos = 0
-                item = 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]
-                    name = conv_name_to_c(target_node.name)
                     arg_values = []
                     for i in range(args):
-                        arg_values.append(str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
+                        arg_values.append(
+                            str(fdt_util.fdt32_to_cpu(prop.value[pos + 1 + i])))
                     pos += 1 + args
-                    # node member is filled with NULL as the real value
-                    # will be update at run-time during dm_init_and_scan()
-                    # by dm_populate_phandle_data()
-                    vals.append('\t{NULL, {%s}}' % (', '.join(arg_values)))
-                    var_node = '%s%s.%s[%d].node' % \
-                                (VAL_PREFIX, var_name, member_name, item)
-                    # Save the the link information to be use to define
-                    # dm_populate_phandle_data()
-                    self._links.append({'var_node': var_node, 'dev_name': name})
-                    item += 1
+                    vals.append('\t{%d, {%s}}' % (target_node.idx,
+                                                  ', '.join(arg_values)))
                 for val in vals:
                     self.buf('\n\t\t%s,' % val)
             else:
@@ -610,6 +638,7 @@ class DtbPlatdata(object):
 
         struct_name, _ = self.get_normalized_compat_name(node)
         var_name = conv_name_to_c(node.name)
+        self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
         self.buf('static struct %s%s %s%s = {\n' %
                  (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
         for pname in sorted(node.props):
@@ -632,6 +661,10 @@ class DtbPlatdata(object):
         self.buf('\t.name\t\t= "%s",\n' % struct_name)
         self.buf('\t.platdata\t= &%s%s,\n' % (VAL_PREFIX, var_name))
         self.buf('\t.platdata_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
+        idx = -1
+        if node.parent and node.parent in self._valid_nodes:
+            idx = node.parent.idx
+        self.buf('\t.parent_idx\t= %d,\n' % idx)
         self.buf('};\n')
         self.buf('\n')
 
@@ -648,6 +681,9 @@ class DtbPlatdata(object):
         information.
         """
         self.out_header()
+        self.out('/* Allow use of U_BOOT_DEVICE() in this file */\n')
+        self.out('#define DT_PLATDATA_C\n')
+        self.out('\n')
         self.out('#include <common.h>\n')
         self.out('#include <dm.h>\n')
         self.out('#include <dt-structs.h>\n')
@@ -669,27 +705,31 @@ class DtbPlatdata(object):
         # nodes using DM_GET_DEVICE
         # dtv_dmc_at_xxx.clocks[0].node = DM_GET_DEVICE(clock_controller_at_xxx)
         self.buf('void dm_populate_phandle_data(void) {\n')
-        for l in self._links:
-            self.buf('\t%s = DM_GET_DEVICE(%s);\n' %
-                     (l['var_node'], l['dev_name']))
         self.buf('}\n')
 
         self.out(''.join(self.get_buf()))
 
 def run_steps(args, dtb_file, include_disabled, output, warning_disabled=False,
-              drivers_additional=[]):
+              drivers_additional=None):
     """Run all the steps of the dtoc tool
 
     Args:
-        args: List of non-option arguments provided to the problem
-        dtb_file: Filename of dtb file to process
-        include_disabled: True to include disabled nodes
-        output: Name of output file
+        args (list): List of non-option arguments provided to the problem
+        dtb_file (str): Filename of dtb file to process
+        include_disabled (bool): True to include disabled nodes
+        output (str): Name of output file
+        warning_disabled (bool): True to avoid showing warnings about missing
+            drivers
+       _drivers_additional (list): List of additional drivers to use during
+            scanning
+    Raises:
+        ValueError: if args has no command, or an unknown command
     """
     if not args:
         raise ValueError('Please specify a command: struct, platdata')
 
-    plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled, drivers_additional)
+    plat = DtbPlatdata(dtb_file, include_disabled, warning_disabled,
+                       drivers_additional)
     plat.scan_drivers()
     plat.scan_dtb()
     plat.scan_tree()
This page took 0.044675 seconds and 4 git commands to generate.