aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/tools/dtoc
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/tools/dtoc
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/tools/dtoc')
-rw-r--r--roms/u-boot/tools/dtoc/.gitignore1
-rw-r--r--roms/u-boot/tools/dtoc/dtb_platdata.py1219
l---------roms/u-boot/tools/dtoc/dtoc1
-rw-r--r--roms/u-boot/tools/dtoc/fdt.py804
-rw-r--r--roms/u-boot/tools/dtoc/fdt_util.py207
-rwxr-xr-xroms/u-boot/tools/dtoc/main.py112
-rw-r--r--roms/u-boot/tools/dtoc/setup.py12
-rw-r--r--roms/u-boot/tools/dtoc/src_scan.py739
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test.dts11
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_add_prop.dts24
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_addr32.dts26
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_addr32_64.dts32
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_addr64.dts32
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_addr64_32.dts32
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad.dts58
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad_path.dts58
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad_uc.dts58
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_aliases.dts22
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_bad_reg.dts17
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_bad_reg2.dts17
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_driver_alias.dts20
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_empty.dts11
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_inst.dts58
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_invalid_driver.dts15
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_noprops.dts21
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_phandle.dts42
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_phandle_bad.dts16
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_phandle_bad2.dts22
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts42
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_phandle_reorder.dts23
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_phandle_single.dts23
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_scan_drivers.cxx5
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_simple.dts63
-rw-r--r--roms/u-boot/tools/dtoc/test/dtoc_test_single_reg.dts30
-rwxr-xr-xroms/u-boot/tools/dtoc/test_dtoc.py1832
l---------roms/u-boot/tools/dtoc/test_fdt1
-rwxr-xr-xroms/u-boot/tools/dtoc/test_fdt.py696
-rw-r--r--roms/u-boot/tools/dtoc/test_src_scan.py492
38 files changed, 6894 insertions, 0 deletions
diff --git a/roms/u-boot/tools/dtoc/.gitignore b/roms/u-boot/tools/dtoc/.gitignore
new file mode 100644
index 000000000..0d20b6487
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/roms/u-boot/tools/dtoc/dtb_platdata.py b/roms/u-boot/tools/dtoc/dtb_platdata.py
new file mode 100644
index 000000000..2d42480a9
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/dtb_platdata.py
@@ -0,0 +1,1219 @@
+#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2017 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+"""Device tree to platform data class
+
+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
+import copy
+from enum import IntEnum
+import os
+import re
+import sys
+
+from dtoc import fdt
+from dtoc import fdt_util
+from dtoc import src_scan
+from dtoc.src_scan import conv_name_to_c
+
+# When we see these properties we ignore them - i.e. do not create a structure
+# member
+PROP_IGNORE_LIST = [
+ '#address-cells',
+ '#gpio-cells',
+ '#size-cells',
+ 'compatible',
+ 'linux,phandle',
+ "status",
+ 'phandle',
+ 'u-boot,dm-pre-reloc',
+ 'u-boot,dm-tpl',
+ 'u-boot,dm-spl',
+]
+
+# 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',
+}
+
+STRUCT_PREFIX = 'dtd_'
+VAL_PREFIX = 'dtv_'
+
+# Properties which are considered to be phandles
+# key: property name
+# value: name of associated #cells property in the target node
+#
+# New phandle properties must be added here; otherwise they will come through as
+# simple integers and finding devices by phandle will not work.
+# Any property that ends with one of these (e.g. 'cd-gpios') will be considered
+# a phandle property.
+PHANDLE_PROPS = {
+ 'clocks': '#clock-cells',
+ 'gpios': '#gpio-cells',
+ 'sandbox,emul': '#emul-cells',
+ }
+
+class Ftype(IntEnum):
+ SOURCE, HEADER = range(2)
+
+
+# This holds information about each type of output file dtoc can create
+# type: Type of file (Ftype)
+# fname: Filename excluding directory, e.g. 'dt-plat.c'
+# hdr_comment: Comment explaining the purpose of the file
+OutputFile = collections.namedtuple('OutputFile',
+ ['ftype', 'fname', 'method', 'hdr_comment'])
+
+# 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'])
+
+# 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 tab_to(num_tabs, line):
+ """Append tabs to a line of text to reach a tab stop.
+
+ Args:
+ num_tabs (int): Tab stop to obtain (0 = column 0, 1 = column 8, etc.)
+ line (str): Line of text to append to
+
+ Returns:
+ 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:
+ return line + ' '
+ return line + '\t' * (num_tabs - len(line) // 8)
+
+def get_value(ftype, value):
+ """Get a value as a C expression
+
+ For integers this returns a byte-swapped (little-endian) hex string
+ For bytes this returns a hex string, e.g. 0x12
+ For strings this returns a literal string enclosed in quotes
+ For booleans this return 'true'
+
+ Args:
+ 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:
+ val = '%#x' % fdt_util.fdt32_to_cpu(value)
+ elif ftype == fdt.Type.BYTE:
+ char = value[0]
+ val = '%#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
+ val = '"%s"' % value.replace('\\', '\\\\')
+ elif ftype == fdt.Type.BOOL:
+ val = 'true'
+ else: # ftype == fdt.Type.INT64:
+ val = '%#x' % value
+ return val
+
+
+class DtbPlatdata():
+ """Provide a means to convert device tree binary data to platform data
+
+ The output of this process is C structures which can be used in space-
+ constrained encvironments where the ~3KB code overhead of device tree
+ code is not affordable.
+
+ Properties:
+ _scan: Scan object, for scanning and reporting on useful information
+ from the U-Boot source code
+ _fdt: Fdt object, referencing the device tree
+ _dtb_fname: Filename of the input device tree binary file
+ _valid_nodes_unsorted: A list of Node object with compatible strings,
+ ordered by devicetree node order
+ _valid_nodes: A list of Node object with compatible strings, 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)
+ _lines: Stashed list of output lines for outputting in the future
+ _dirname: Directory to hold output files, or None for none (all files
+ go to stdout)
+ _struct_data (dict): OrderedDict of dtplat structures to output
+ key (str): Node name, as a C identifier
+ value: dict containing structure fields:
+ key (str): Field name
+ value: Prop object with field information
+ _basedir (str): Base directory of source tree
+ _valid_uclasses (list of src_scan.Uclass): List of uclasses needed for
+ the selected devices (see _valid_node), in alphabetical order
+ _instantiate: Instantiate devices so they don't need to be bound at
+ run-time
+ """
+ def __init__(self, scan, dtb_fname, include_disabled, instantiate=False):
+ self._scan = scan
+ self._fdt = None
+ self._dtb_fname = dtb_fname
+ self._valid_nodes = None
+ self._valid_nodes_unsorted = None
+ self._include_disabled = include_disabled
+ self._outfile = None
+ self._lines = []
+ self._dirnames = [None] * len(Ftype)
+ self._struct_data = collections.OrderedDict()
+ self._basedir = None
+ self._valid_uclasses = None
+ self._instantiate = instantiate
+
+ def setup_output_dirs(self, output_dirs):
+ """Set up the output directories
+
+ This should be done before setup_output() is called
+
+ Args:
+ output_dirs (tuple of str):
+ Directory to use for C output files.
+ Use None to write files relative current directory
+ Directory to use for H output files.
+ Defaults to the C output dir
+ """
+ def process_dir(ftype, dirname):
+ if dirname:
+ os.makedirs(dirname, exist_ok=True)
+ self._dirnames[ftype] = dirname
+
+ if output_dirs:
+ c_dirname = output_dirs[0]
+ h_dirname = output_dirs[1] if len(output_dirs) > 1 else c_dirname
+ process_dir(Ftype.SOURCE, c_dirname)
+ process_dir(Ftype.HEADER, h_dirname)
+
+ def setup_output(self, ftype, fname):
+ """Set up the output destination
+
+ Once this is done, future calls to self.out() will output to this
+ file. The file used is as follows:
+
+ self._dirnames[ftype] is None: output to fname, or stdout if None
+ self._dirnames[ftype] is not None: output to fname in that directory
+
+ Calling this function multiple times will close the old file and open
+ the new one. If they are the same file, nothing happens and output will
+ continue to the same file.
+
+ Args:
+ ftype (str): Type of file to create ('c' or 'h')
+ fname (str): Filename to send output to. If there is a directory in
+ self._dirnames for this file type, it will be put in that
+ directory
+ """
+ dirname = self._dirnames[ftype]
+ if dirname:
+ pathname = os.path.join(dirname, fname)
+ if self._outfile:
+ self._outfile.close()
+ self._outfile = open(pathname, 'w')
+ elif fname:
+ if not self._outfile:
+ self._outfile = open(fname, 'w')
+ else:
+ self._outfile = sys.stdout
+
+ def finish_output(self):
+ """Finish outputing to a file
+
+ This closes the output file, if one is in use
+ """
+ if self._outfile != sys.stdout:
+ self._outfile.close()
+ self._outfile = None
+
+ def out(self, line):
+ """Output a string to the output file
+
+ Args:
+ line (str): String to output
+ """
+ self._outfile.write(line)
+
+ def buf(self, line):
+ """Buffer up a string to send later
+
+ Args:
+ line (str): String to add to our 'buffer' list
+ """
+ self._lines.append(line)
+
+ def get_buf(self):
+ """Get the contents of the output buffer, and clear it
+
+ Returns:
+ list(str): The output buffer, which is then cleared for future use
+ """
+ lines = self._lines
+ self._lines = []
+ return lines
+
+ def out_header(self, outfile):
+ """Output a message indicating that this is an auto-generated file
+
+ Args:
+ outfile: OutputFile describing the file being generated
+ """
+ self.out('''/*
+ * DO NOT MODIFY
+ *
+ * %s.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+''' % outfile.hdr_comment)
+
+ 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 (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
+ """
+ cells_prop = None
+ for name, cprop in PHANDLE_PROPS.items():
+ if prop.name.endswith(name):
+ cells_prop = cprop
+ if cells_prop:
+ if not isinstance(prop.value, list):
+ prop.value = [prop.value]
+ val = prop.value
+ i = 0
+
+ max_args = 0
+ args = []
+ while i < len(val):
+ phandle = fdt_util.fdt32_to_cpu(val[i])
+ # If we get to the end of the list, stop. This can happen
+ # since some nodes have more phandles in the list than others,
+ # but we allocate enough space for the largest list. So those
+ # nodes with shorter lists end up with zeroes at the end.
+ if not phandle:
+ break
+ target = self._fdt.phandle_to_node.get(phandle)
+ if not target:
+ raise ValueError("Cannot parse '%s' in node '%s'" %
+ (prop.name, node_name))
+ cells = target.props.get(cells_prop)
+ if not cells:
+ raise ValueError("Node '%s' has no cells property" %
+ target.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
+
+ Once this is done, self._fdt.GetRoot() can be called to obtain the
+ device tree root node, and progress from there.
+ """
+ self._fdt = fdt.FdtScan(self._dtb_fname)
+
+ def scan_node(self, node, valid_nodes):
+ """Scan a node and subnodes to build a tree of node and phandle info
+
+ This adds each subnode to self._valid_nodes if it is enabled and has a
+ compatible string.
+
+ Args:
+ node (Node): Node for scan for subnodes
+ valid_nodes (list of Node): List of Node objects to add to
+ """
+ for subnode in node.subnodes:
+ if 'compatible' in subnode.props:
+ status = subnode.props.get('status')
+ if (not self._include_disabled and not status or
+ status.value != 'disabled'):
+ valid_nodes.append(subnode)
+
+ # recurse to handle any subnodes
+ self.scan_node(subnode, valid_nodes)
+
+ def scan_tree(self, add_root):
+ """Scan the device tree for useful information
+
+ This fills in the following properties:
+ _valid_nodes_unsorted: A list of nodes we wish to consider include
+ in the platform data (in devicetree node order)
+ _valid_nodes: Sorted version of _valid_nodes_unsorted
+
+ Args:
+ add_root: True to add the root node also (which wouldn't normally
+ be added as it may not have a compatible string)
+ """
+ root = self._fdt.GetRoot()
+ valid_nodes = []
+ if add_root:
+ valid_nodes.append(root)
+ self.scan_node(root, valid_nodes)
+ self._valid_nodes_unsorted = valid_nodes
+ self._valid_nodes = sorted(valid_nodes,
+ key=lambda x: conv_name_to_c(x.name))
+
+ def prepare_nodes(self):
+ """Add extra properties to the nodes we are using
+
+ The following properties are added for use by dtoc:
+ idx: Index number of this node (0=first, etc.)
+ struct_name: Name of the struct dtd used by this node
+ var_name: C name for this node
+ child_devs: List of child devices for this node, each a None
+ child_refs: Dict of references for each child:
+ key: Position in child list (-1=head, 0=first, 1=second, ...
+ n-1=last, n=head)
+ seq: Sequence number of the device (unique within its uclass), or
+ -1 not not known yet
+ dev_ref: Reference to this device, e.g. 'DM_DEVICE_REF(serial)'
+ driver: Driver record for this node, or None if not known
+ uclass: Uclass record for this node, or None if not known
+ uclass_seq: Position of this device within the uclass list (0=first,
+ n-1=last)
+ parent_seq: Position of this device within it siblings (0=first,
+ n-1=last)
+ parent_driver: Driver record of the node's parent, or None if none.
+ We don't use node.parent.driver since node.parent may not be in
+ the list of valid nodes
+ """
+ for idx, node in enumerate(self._valid_nodes):
+ node.idx = idx
+ node.struct_name, _ = self._scan.get_normalized_compat_name(node)
+ node.var_name = conv_name_to_c(node.name)
+ node.child_devs = []
+ node.child_refs = {}
+ node.seq = -1
+ node.dev_ref = None
+ node.driver = None
+ node.uclass = None
+ node.uclass_seq = None
+ node.parent_seq = None
+ node.parent_driver = None
+
+ @staticmethod
+ def get_num_cells(node):
+ """Get the number of cells in addresses and sizes for this node
+
+ Args:
+ node (fdt.None): Node to check
+
+ Returns:
+ Tuple:
+ Number of address cells for this node
+ Number of size cells for this node
+ """
+ parent = node.parent
+ if parent and not parent.props:
+ raise ValueError("Parent node '%s' has no properties - do you need u-boot,dm-spl or similar?" %
+ parent.path)
+ num_addr, num_size = 2, 2
+ if parent:
+ 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
+
+ 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
+ num_addr, num_size = self.get_num_cells(node)
+ total = num_addr + num_size
+
+ if reg.type != fdt.Type.INT:
+ raise ValueError("Node '%s' reg property is not an int" %
+ node.name)
+ if not isinstance(reg.value, list):
+ reg.value = [reg.value]
+ if len(reg.value) % total:
+ raise ValueError(
+ "Node '%s' (parent '%s') reg property has %d cells "
+ 'which is not a multiple of na + ns = %d + %d)' %
+ (node.name, node.parent.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
+ while i < len(val):
+ 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
+
+ def scan_structs(self):
+ """Scan the device tree building up the C structures we will use.
+
+ Build a dict keyed by C struct name containing a dict of Prop
+ object for each struct field (keyed by property name). Where the
+ same struct appears multiple times, try to use the 'widest'
+ property, i.e. the one with a type which can express all others.
+
+ Once the widest property is determined, all other properties are
+ updated to match that width.
+
+ The results are written to self._struct_data
+ """
+ structs = self._struct_data
+ for node in self._valid_nodes:
+ fields = {}
+
+ # Get a list of all the valid properties in this node.
+ for name, prop in node.props.items():
+ if name not in PROP_IGNORE_LIST and name[0] != '#':
+ fields[name] = copy.deepcopy(prop)
+
+ # If we've seen this struct_name before, update the existing struct
+ if node.struct_name in structs:
+ struct = structs[node.struct_name]
+ for name, prop in fields.items():
+ oldprop = struct.get(name)
+ if oldprop:
+ oldprop.Widen(prop)
+ else:
+ struct[name] = prop
+
+ # Otherwise store this as a new struct.
+ else:
+ structs[node.struct_name] = fields
+
+ for node in self._valid_nodes:
+ struct = structs[node.struct_name]
+ for name, prop in node.props.items():
+ if name not in PROP_IGNORE_LIST and name[0] != '#':
+ prop.Widen(struct[name])
+
+ def scan_phandles(self):
+ """Figure out what phandles each node uses
+
+ We need to be careful when outputing nodes that use phandles since
+ they must come after the declaration of the phandles in the C file.
+ Otherwise we get a compiler error since the phandle struct is not yet
+ declared.
+
+ This function adds to each node a list of phandle nodes that the node
+ depends on. This allows us to output things in the right order.
+ """
+ for node in self._valid_nodes:
+ node.phandles = set()
+ for pname, prop in node.props.items():
+ if pname in PROP_IGNORE_LIST or pname[0] == '#':
+ continue
+ info = self.get_phandle_argc(prop, node.name)
+ if info:
+ # 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):
+ """Generate struct defintions for the platform data
+
+ 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.
+ """
+ structs = self._struct_data
+ self.out('#include <stdbool.h>\n')
+ self.out('#include <linux/libfdt.h>\n')
+
+ # Output the struct definition
+ for name in sorted(structs):
+ self.out('struct %s%s {\n' % (STRUCT_PREFIX, name))
+ for pname in sorted(structs[name]):
+ prop = structs[name][pname]
+ info = self.get_phandle_argc(prop, structs[name])
+ if info:
+ # For phandles, include a reference to the target
+ 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(info.args)))
+ else:
+ ptype = TYPE_NAMES[prop.type]
+ self.out('\t%s%s' % (tab_to(2, ptype),
+ conv_name_to_c(prop.name)))
+ if isinstance(prop.value, list):
+ self.out('[%d]' % len(prop.value))
+ self.out(';\n')
+ self.out('};\n')
+
+ def _output_list(self, node, prop):
+ """Output the C code for a devicetree property that holds a list
+
+ Args:
+ node (fdt.Node): Node to output
+ prop (fdt.Prop): Prop to output
+ """
+ self.buf('{')
+ vals = []
+ # For phandles, output a reference to the platform data
+ # of the target node.
+ info = self.get_phandle_argc(prop, node.name)
+ if info:
+ # 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]
+ 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{%d, {%s}}' % (target_node.idx,
+ ', '.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))
+
+ # Put 8 values per line to avoid very long lines.
+ for i in range(0, len(vals), 8):
+ if i:
+ self.buf(',\n\t\t')
+ self.buf(', '.join(vals[i:i + 8]))
+ self.buf('}')
+
+ def _declare_device(self, node):
+ """Add a device declaration to the output
+
+ This declares a U_BOOT_DRVINFO() for the device being processed
+
+ Args:
+ node: Node to process
+ """
+ self.buf('U_BOOT_DRVINFO(%s) = {\n' % node.var_name)
+ self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
+ self.buf('\t.plat\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
+ self.buf('\t.plat_size\t= sizeof(%s%s),\n' %
+ (VAL_PREFIX, node.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')
+
+ def prep_priv(self, struc, name, suffix, section='.priv_data'):
+ if not struc:
+ return None
+ var_name = '_%s%s' % (name, suffix)
+ hdr = self._scan._structs.get(struc)
+ if hdr:
+ self.buf('#include <%s>\n' % hdr.fname)
+ else:
+ print('Warning: Cannot find header file for struct %s' % struc)
+ attr = '__attribute__ ((section ("%s")))' % section
+ return var_name, struc, attr
+
+ def alloc_priv(self, info, name, extra, suffix='_priv'):
+ result = self.prep_priv(info, name, suffix)
+ if not result:
+ return None
+ var_name, struc, section = result
+ self.buf('u8 %s_%s[sizeof(struct %s)]\n\t%s;\n' %
+ (var_name, extra, struc.strip(), section))
+ return '%s_%s' % (var_name, extra)
+
+ def alloc_plat(self, info, name, extra, node):
+ result = self.prep_priv(info, name, '_plat')
+ if not result:
+ return None
+ var_name, struc, section = result
+ self.buf('struct %s %s\n\t%s_%s = {\n' %
+ (struc.strip(), section, var_name, extra))
+ self.buf('\t.dtplat = {\n')
+ for pname in sorted(node.props):
+ self._output_prop(node, node.props[pname], 2)
+ self.buf('\t},\n')
+ self.buf('};\n')
+ return '&%s_%s' % (var_name, extra)
+
+ def _declare_device_inst(self, node, parent_driver):
+ """Add a device instance declaration to the output
+
+ This declares a DM_DEVICE_INST() for the device being processed
+
+ Args:
+ node: Node to output
+ """
+ driver = node.driver
+ uclass = node.uclass
+ self.buf('\n')
+ num_lines = len(self._lines)
+ plat_name = self.alloc_plat(driver.plat, driver.name, node.var_name,
+ node)
+ priv_name = self.alloc_priv(driver.priv, driver.name, node.var_name)
+ parent_plat_name = None
+ parent_priv_name = None
+ if parent_driver:
+ # TODO: deal with uclass providing these values
+ parent_plat_name = self.alloc_priv(
+ parent_driver.child_plat, driver.name, node.var_name,
+ '_parent_plat')
+ parent_priv_name = self.alloc_priv(
+ parent_driver.child_priv, driver.name, node.var_name,
+ '_parent_priv')
+ uclass_plat_name = self.alloc_priv(
+ uclass.per_dev_plat, driver.name + '_uc', node.var_name, 'plat')
+ uclass_priv_name = self.alloc_priv(uclass.per_dev_priv,
+ driver.name + '_uc', node.var_name)
+ for hdr in driver.headers:
+ self.buf('#include %s\n' % hdr)
+
+ # Add a blank line if we emitted any stuff above, for readability
+ if num_lines != len(self._lines):
+ self.buf('\n')
+
+ self.buf('DM_DEVICE_INST(%s) = {\n' % node.var_name)
+ self.buf('\t.driver\t\t= DM_DRIVER_REF(%s),\n' % node.struct_name)
+ self.buf('\t.name\t\t= "%s",\n' % node.struct_name)
+ if plat_name:
+ self.buf('\t.plat_\t\t= %s,\n' % plat_name)
+ else:
+ self.buf('\t.plat_\t\t= &%s%s,\n' % (VAL_PREFIX, node.var_name))
+ if parent_plat_name:
+ self.buf('\t.parent_plat_\t= %s,\n' % parent_plat_name)
+ if uclass_plat_name:
+ self.buf('\t.uclass_plat_\t= %s,\n' % uclass_plat_name)
+ driver_date = None
+
+ if node != self._fdt.GetRoot():
+ compat_list = node.props['compatible'].value
+ if not isinstance(compat_list, list):
+ compat_list = [compat_list]
+ for compat in compat_list:
+ driver_data = driver.compat.get(compat)
+ if driver_data:
+ self.buf('\t.driver_data\t= %s,\n' % driver_data)
+ break
+
+ if node.parent and node.parent.parent:
+ self.buf('\t.parent\t\t= DM_DEVICE_REF(%s),\n' %
+ node.parent.var_name)
+ if priv_name:
+ self.buf('\t.priv_\t\t= %s,\n' % priv_name)
+ self.buf('\t.uclass\t\t= DM_UCLASS_REF(%s),\n' % uclass.name)
+
+ if uclass_priv_name:
+ self.buf('\t.uclass_priv_ = %s,\n' % uclass_priv_name)
+ if parent_priv_name:
+ self.buf('\t.parent_priv_\t= %s,\n' % parent_priv_name)
+ self.list_node('uclass_node', uclass.node_refs, node.uclass_seq)
+ self.list_head('child_head', 'sibling_node', node.child_devs, node.var_name)
+ if node.parent in self._valid_nodes:
+ self.list_node('sibling_node', node.parent.child_refs,
+ node.parent_seq)
+ # flags is left as 0
+
+ self.buf('\t.seq_ = %d,\n' % node.seq)
+
+ self.buf('};\n')
+ self.buf('\n')
+ return parent_plat_name
+
+ def _output_prop(self, node, prop, tabs=1):
+ """Output a line containing the value of a struct member
+
+ Args:
+ node (Node): Node being output
+ prop (Prop): Prop object to output
+ """
+ if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
+ return
+ member_name = conv_name_to_c(prop.name)
+ self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
+
+ # Special handling for lists
+ if isinstance(prop.value, list):
+ self._output_list(node, prop)
+ else:
+ self.buf(get_value(prop.type, prop.value))
+ self.buf(',\n')
+
+ def _output_values(self, node):
+ """Output the definition of a device's struct values
+
+ Args:
+ node (Node): Node to output
+ """
+ self.buf('static struct %s%s %s%s = {\n' %
+ (STRUCT_PREFIX, node.struct_name, VAL_PREFIX, node.var_name))
+ for pname in sorted(node.props):
+ self._output_prop(node, node.props[pname])
+ self.buf('};\n')
+
+ def list_head(self, head_member, node_member, node_refs, var_name):
+ self.buf('\t.%s\t= {\n' % head_member)
+ if node_refs:
+ last = node_refs[-1].dev_ref
+ first = node_refs[0].dev_ref
+ member = node_member
+ else:
+ last = 'DM_DEVICE_REF(%s)' % var_name
+ first = last
+ member = head_member
+ self.buf('\t\t.prev = &%s->%s,\n' % (last, member))
+ self.buf('\t\t.next = &%s->%s,\n' % (first, member))
+ self.buf('\t},\n')
+
+ def list_node(self, member, node_refs, seq):
+ self.buf('\t.%s\t= {\n' % member)
+ self.buf('\t\t.prev = %s,\n' % node_refs[seq - 1])
+ self.buf('\t\t.next = %s,\n' % node_refs[seq + 1])
+ self.buf('\t},\n')
+
+ def generate_uclasses(self):
+ self.out('\n')
+ self.out('#include <common.h>\n')
+ self.out('#include <dm.h>\n')
+ self.out('#include <dt-structs.h>\n')
+ self.out('\n')
+ self.buf('/*\n')
+ self.buf(
+ " * uclass declarations, ordered by 'struct uclass' linker_list idx:\n")
+ uclass_list = self._valid_uclasses
+ for seq, uclass in enumerate(uclass_list):
+ self.buf(' * %3d: %s\n' % (seq, uclass.name))
+ self.buf(' *\n')
+ self.buf(' * Sequence numbers allocated in each uclass:\n')
+ for uclass in uclass_list:
+ if uclass.alias_num_to_node:
+ self.buf(' * %s: %s\n' % (uclass.name, uclass.uclass_id))
+ for seq, node in uclass.alias_num_to_node.items():
+ self.buf(' * %d: %s\n' % (seq, node.path))
+ self.buf(' */\n')
+
+ uclass_node = {}
+ for seq, uclass in enumerate(uclass_list):
+ uclass_node[seq] = ('&DM_UCLASS_REF(%s)->sibling_node' %
+ uclass.name)
+ uclass_node[-1] = '&uclass_head'
+ uclass_node[len(uclass_list)] = '&uclass_head'
+ self.buf('\n')
+ self.buf('struct list_head %s = {\n' % 'uclass_head')
+ self.buf('\t.prev = %s,\n' % uclass_node[len(uclass_list) -1])
+ self.buf('\t.next = %s,\n' % uclass_node[0])
+ self.buf('};\n')
+ self.buf('\n')
+
+ for seq, uclass in enumerate(uclass_list):
+ uc_drv = self._scan._uclass.get(uclass.uclass_id)
+
+ priv_name = self.alloc_priv(uc_drv.priv, uc_drv.name, '')
+
+ self.buf('DM_UCLASS_INST(%s) = {\n' % uclass.name)
+ if priv_name:
+ self.buf('\t.priv_\t\t= %s,\n' % priv_name)
+ self.buf('\t.uc_drv\t\t= DM_UCLASS_DRIVER_REF(%s),\n' % uclass.name)
+ self.list_node('sibling_node', uclass_node, seq)
+ self.list_head('dev_head', 'uclass_node', uc_drv.devs, None)
+ self.buf('};\n')
+ self.buf('\n')
+ self.out(''.join(self.get_buf()))
+
+ def read_aliases(self):
+ """Read the aliases and attach the information to self._alias
+
+ Raises:
+ ValueError: The alias path is not found
+ """
+ alias_node = self._fdt.GetNode('/aliases')
+ if not alias_node:
+ return
+ re_num = re.compile('(^[a-z0-9-]+[a-z]+)([0-9]+)$')
+ for prop in alias_node.props.values():
+ m_alias = re_num.match(prop.name)
+ if not m_alias:
+ raise ValueError("Cannot decode alias '%s'" % prop.name)
+ name, num = m_alias.groups()
+ node = self._fdt.GetNode(prop.value)
+ result = self._scan.add_uclass_alias(name, num, node)
+ if result is None:
+ raise ValueError("Alias '%s' path '%s' not found" %
+ (prop.name, prop.value))
+ elif result is False:
+ print("Could not find uclass for alias '%s'" % prop.name)
+
+ def generate_decl(self):
+ nodes_to_output = list(self._valid_nodes)
+
+ self.buf('#include <dm/device-internal.h>\n')
+ self.buf('#include <dm/uclass-internal.h>\n')
+ self.buf('\n')
+ self.buf(
+ '/* driver declarations - these allow DM_DRIVER_GET() to be used */\n')
+ for node in nodes_to_output:
+ self.buf('extern U_BOOT_DRIVER(%s);\n' % node.struct_name);
+ self.buf('\n')
+
+ if self._instantiate:
+ self.buf(
+ '/* device declarations - these allow DM_DEVICE_REF() to be used */\n')
+ for node in nodes_to_output:
+ self.buf('extern DM_DEVICE_INST(%s);\n' % node.var_name)
+ self.buf('\n')
+
+ uclass_list = self._valid_uclasses
+
+ self.buf(
+ '/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */\n')
+ for uclass in uclass_list:
+ self.buf('extern UCLASS_DRIVER(%s);\n' % uclass.name)
+
+ if self._instantiate:
+ self.buf('\n')
+ self.buf('/* uclass declarations - needed for DM_UCLASS_REF() */\n')
+ for uclass in uclass_list:
+ self.buf('extern DM_UCLASS_INST(%s);\n' % uclass.name)
+ self.out(''.join(self.get_buf()))
+
+ def assign_seqs(self):
+ """Assign a sequence number to each node"""
+ for node in self._valid_nodes_unsorted:
+ seq = self._scan.assign_seq(node)
+ if seq is not None:
+ node.seq = seq
+
+ def process_nodes(self, need_drivers):
+ nodes_to_output = list(self._valid_nodes)
+
+ # Figure out which drivers we actually use
+ self._scan.mark_used(nodes_to_output)
+
+ for node in nodes_to_output:
+ node.dev_ref = 'DM_DEVICE_REF(%s)' % node.var_name
+ driver = self._scan.get_driver(node.struct_name)
+ if not driver:
+ if not need_drivers:
+ continue
+ raise ValueError("Cannot parse/find driver for '%s'" %
+ node.struct_name)
+ node.driver = driver
+ uclass = self._scan._uclass.get(driver.uclass_id)
+ if not uclass:
+ raise ValueError("Cannot parse/find uclass '%s' for driver '%s'" %
+ (driver.uclass_id, node.struct_name))
+ node.uclass = uclass
+ node.uclass_seq = len(node.uclass.devs)
+ node.uclass.devs.append(node)
+ uclass.node_refs[node.uclass_seq] = \
+ '&%s->uclass_node' % node.dev_ref
+
+ parent_driver = None
+ if node.parent in self._valid_nodes:
+ parent_driver = self._scan.get_driver(node.parent.struct_name)
+ if not parent_driver:
+ if not need_drivers:
+ continue
+ raise ValueError(
+ "Cannot parse/find parent driver '%s' for '%s'" %
+ (node.parent.struct_name, node.struct_name))
+ node.parent_seq = len(node.parent.child_devs)
+ node.parent.child_devs.append(node)
+ node.parent.child_refs[node.parent_seq] = \
+ '&%s->sibling_node' % node.dev_ref
+ node.parent_driver = parent_driver
+
+ for node in nodes_to_output:
+ ref = '&%s->child_head' % node.dev_ref
+ node.child_refs[-1] = ref
+ node.child_refs[len(node.child_devs)] = ref
+
+ uclass_set = set()
+ for driver in self._scan._drivers.values():
+ if driver.used and driver.uclass:
+ uclass_set.add(driver.uclass)
+ self._valid_uclasses = sorted(list(uclass_set),
+ key=lambda uc: uc.uclass_id)
+
+ for seq, uclass in enumerate(uclass_set):
+ ref = '&DM_UCLASS_REF(%s)->dev_head' % uclass.name
+ uclass.node_refs[-1] = ref
+ uclass.node_refs[len(uclass.devs)] = ref
+
+ def output_node_plat(self, node):
+ """Output the C code for a node
+
+ Args:
+ node (fdt.Node): node to output
+ """
+ driver = node.driver
+ parent_driver = node.parent_driver
+
+ line1 = 'Node %s index %d' % (node.path, node.idx)
+ if driver:
+ self.buf('/*\n')
+ self.buf(' * %s\n' % line1)
+ self.buf(' * driver %s parent %s\n' % (driver.name,
+ parent_driver.name if parent_driver else 'None'))
+ self.buf(' */\n')
+ else:
+ self.buf('/* %s */\n' % line1)
+
+ self._output_values(node)
+ self._declare_device(node)
+
+ self.out(''.join(self.get_buf()))
+
+ def output_node_instance(self, node):
+ """Output the C code for a node
+
+ Args:
+ node (fdt.Node): node to output
+ """
+ parent_driver = node.parent_driver
+
+ self.buf('/*\n')
+ self.buf(' * Node %s index %d\n' % (node.path, node.idx))
+ self.buf(' * driver %s parent %s\n' % (node.driver.name,
+ parent_driver.name if parent_driver else 'None'))
+ self.buf('*/\n')
+
+ if not node.driver.plat:
+ self._output_values(node)
+ self._declare_device_inst(node, parent_driver)
+
+ self.out(''.join(self.get_buf()))
+
+ def generate_plat(self):
+ """Generate device defintions for the platform data
+
+ This writes out C platform data initialisation data and
+ U_BOOT_DRVINFO() declarations for each valid node. Where a node has
+ multiple compatible strings, a #define is used to make them equivalent.
+
+ See the documentation in doc/driver-model/of-plat.rst for more
+ information.
+ """
+ self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
+ self.out('#define DT_PLAT_C\n')
+ self.out('\n')
+ self.out('#include <common.h>\n')
+ self.out('#include <dm.h>\n')
+ self.out('#include <dt-structs.h>\n')
+ self.out('\n')
+
+ if self._valid_nodes:
+ self.out('/*\n')
+ self.out(
+ " * driver_info declarations, ordered by 'struct driver_info' linker_list idx:\n")
+ self.out(' *\n')
+ self.out(' * idx %-20s %-s\n' % ('driver_info', 'driver'))
+ self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
+ for node in self._valid_nodes:
+ self.out(' * %3d: %-20s %-s\n' %
+ (node.idx, node.var_name, node.struct_name))
+ self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
+ self.out(' */\n')
+ self.out('\n')
+
+ for node in self._valid_nodes:
+ self.output_node_plat(node)
+
+ self.out(''.join(self.get_buf()))
+
+ def generate_device(self):
+ """Generate device instances
+
+ This writes out DM_DEVICE_INST() records for each device in the
+ build.
+
+ See the documentation in doc/driver-model/of-plat.rst for more
+ information.
+ """
+ self.out('#include <common.h>\n')
+ self.out('#include <dm.h>\n')
+ self.out('#include <dt-structs.h>\n')
+ self.out('\n')
+
+ if self._valid_nodes:
+ self.out('/*\n')
+ self.out(
+ " * udevice declarations, ordered by 'struct udevice' linker_list position:\n")
+ self.out(' *\n')
+ self.out(' * idx %-20s %-s\n' % ('udevice', 'driver'))
+ self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
+ for node in self._valid_nodes:
+ self.out(' * %3d: %-20s %-s\n' %
+ (node.idx, node.var_name, node.struct_name))
+ self.out(' * --- %-20s %-s\n' % ('-' * 20, '-' * 20))
+ self.out(' */\n')
+ self.out('\n')
+
+ for node in self._valid_nodes:
+ self.output_node_instance(node)
+
+ self.out(''.join(self.get_buf()))
+
+
+# Types of output file we understand
+# key: Command used to generate this file
+# value: OutputFile for this command
+OUTPUT_FILES_COMMON = {
+ 'decl':
+ OutputFile(Ftype.HEADER, 'dt-decl.h', DtbPlatdata.generate_decl,
+ 'Declares externs for all device/uclass instances'),
+ 'struct':
+ OutputFile(Ftype.HEADER, 'dt-structs-gen.h',
+ DtbPlatdata.generate_structs,
+ 'Defines the structs used to hold devicetree data'),
+ }
+
+# File generated without instantiate
+OUTPUT_FILES_NOINST = {
+ 'platdata':
+ OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
+ 'Declares the U_BOOT_DRIVER() records and platform data'),
+ }
+
+# File generated with instantiate
+OUTPUT_FILES_INST = {
+ 'device':
+ OutputFile(Ftype.SOURCE, 'dt-device.c', DtbPlatdata.generate_device,
+ 'Declares the DM_DEVICE_INST() records'),
+ 'uclass':
+ OutputFile(Ftype.SOURCE, 'dt-uclass.c', DtbPlatdata.generate_uclasses,
+ 'Declares the uclass instances (struct uclass)'),
+ }
+
+
+def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
+ instantiate, warning_disabled=False, drivers_additional=None,
+ basedir=None, scan=None):
+ """Run all the steps of the dtoc tool
+
+ Args:
+ 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 (None for stdout)
+ output_dirs (tuple of str):
+ Directory to put C output files
+ Directory to put H output files
+ phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
+ or 'tpl'. None if not known
+ instantiate: Instantiate devices so they don't need to be bound at
+ run-time
+ warning_disabled (bool): True to avoid showing warnings about missing
+ drivers
+ drivers_additional (list): List of additional drivers to use during
+ scanning
+ basedir (str): Base directory of U-Boot source code. Defaults to the
+ grandparent of this file's directory
+ scan (src_src.Scanner): Scanner from a previous run. This can help speed
+ up tests. Use None for normal operation
+
+ Returns:
+ DtbPlatdata object
+
+ Raises:
+ ValueError: if args has no command, or an unknown command
+ """
+ if not args:
+ raise ValueError('Please specify a command: struct, platdata, all')
+ if output and output_dirs and any(output_dirs):
+ raise ValueError('Must specify either output or output_dirs, not both')
+
+ if not scan:
+ scan = src_scan.Scanner(basedir, drivers_additional, phase)
+ scan.scan_drivers()
+ do_process = True
+ else:
+ do_process = False
+ plat = DtbPlatdata(scan, dtb_file, include_disabled, instantiate)
+ plat.scan_dtb()
+ plat.scan_tree(add_root=instantiate)
+ plat.prepare_nodes()
+ plat.scan_reg_sizes()
+ plat.setup_output_dirs(output_dirs)
+ plat.scan_structs()
+ plat.scan_phandles()
+ plat.process_nodes(instantiate)
+ plat.read_aliases()
+ plat.assign_seqs()
+
+ # Figure out what output files we plan to generate
+ output_files = dict(OUTPUT_FILES_COMMON)
+ if instantiate:
+ output_files.update(OUTPUT_FILES_INST)
+ else:
+ output_files.update(OUTPUT_FILES_NOINST)
+
+ cmds = args[0].split(',')
+ if 'all' in cmds:
+ cmds = sorted(output_files.keys())
+ for cmd in cmds:
+ outfile = output_files.get(cmd)
+ if not outfile:
+ raise ValueError("Unknown command '%s': (use: %s)" %
+ (cmd, ', '.join(sorted(output_files.keys()))))
+ plat.setup_output(outfile.ftype,
+ outfile.fname if output_dirs else output)
+ plat.out_header(outfile)
+ outfile.method(plat)
+ plat.finish_output()
+
+ if not warning_disabled:
+ scan.show_warnings()
+ return plat
diff --git a/roms/u-boot/tools/dtoc/dtoc b/roms/u-boot/tools/dtoc/dtoc
new file mode 120000
index 000000000..11a5d8e18
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/dtoc
@@ -0,0 +1 @@
+main.py \ No newline at end of file
diff --git a/roms/u-boot/tools/dtoc/fdt.py b/roms/u-boot/tools/dtoc/fdt.py
new file mode 100644
index 000000000..3996971e3
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/fdt.py
@@ -0,0 +1,804 @@
+#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+from enum import IntEnum
+import struct
+import sys
+
+from dtoc import fdt_util
+import libfdt
+from libfdt import QUIET_NOTFOUND
+from patman import tools
+
+# This deals with a device tree, presenting it as an assortment of Node and
+# Prop objects, representing nodes and properties, respectively. This file
+# contains the base classes and defines the high-level API. You can use
+# FdtScan() as a convenience function to create and scan an Fdt.
+
+# This implementation uses a libfdt Python library to access the device tree,
+# so it is fairly efficient.
+
+# A list of types we support
+class Type(IntEnum):
+ (BYTE, INT, STRING, BOOL, INT64) = range(5)
+
+ def is_wider_than(self, other):
+ """Check if another type is 'wider' than this one
+
+ A wider type is one that holds more information than an earlier one,
+ similar to the concept of type-widening in C.
+
+ This uses a simple arithmetic comparison, since type values are in order
+ from narrowest (BYTE) to widest (INT64).
+
+ Args:
+ other: Other type to compare against
+
+ Return:
+ True if the other type is wider
+ """
+ return self.value > other.value
+
+def CheckErr(errnum, msg):
+ if errnum:
+ raise ValueError('Error %d: %s: %s' %
+ (errnum, libfdt.fdt_strerror(errnum), msg))
+
+
+def BytesToValue(data):
+ """Converts a string of bytes into a type and value
+
+ Args:
+ A bytes value (which on Python 2 is an alias for str)
+
+ Return:
+ A tuple:
+ Type of data
+ Data, either a single element or a list of elements. Each element
+ is one of:
+ Type.STRING: str/bytes value from the property
+ Type.INT: a byte-swapped integer stored as a 4-byte str/bytes
+ Type.BYTE: a byte stored as a single-byte str/bytes
+ """
+ data = bytes(data)
+ size = len(data)
+ strings = data.split(b'\0')
+ is_string = True
+ count = len(strings) - 1
+ if count > 0 and not len(strings[-1]):
+ for string in strings[:-1]:
+ if not string:
+ is_string = False
+ break
+ for ch in string:
+ if ch < 32 or ch > 127:
+ is_string = False
+ break
+ else:
+ is_string = False
+ if is_string:
+ if count == 1:
+ return Type.STRING, strings[0].decode()
+ else:
+ return Type.STRING, [s.decode() for s in strings[:-1]]
+ if size % 4:
+ if size == 1:
+ return Type.BYTE, chr(data[0])
+ else:
+ return Type.BYTE, [chr(ch) for ch in list(data)]
+ val = []
+ for i in range(0, size, 4):
+ val.append(data[i:i + 4])
+ if size == 4:
+ return Type.INT, val[0]
+ else:
+ return Type.INT, val
+
+
+class Prop:
+ """A device tree property
+
+ Properties:
+ node: Node containing this property
+ offset: Offset of the property (None if still to be synced)
+ name: Property name (as per the device tree)
+ value: Property value as a string of bytes, or a list of strings of
+ bytes
+ type: Value type
+ """
+ def __init__(self, node, offset, name, data):
+ self._node = node
+ self._offset = offset
+ self.name = name
+ self.value = None
+ self.bytes = bytes(data)
+ self.dirty = offset is None
+ if not data:
+ self.type = Type.BOOL
+ self.value = True
+ return
+ self.type, self.value = BytesToValue(bytes(data))
+
+ def RefreshOffset(self, poffset):
+ self._offset = poffset
+
+ def Widen(self, newprop):
+ """Figure out which property type is more general
+
+ Given a current property and a new property, this function returns the
+ one that is less specific as to type. The less specific property will
+ be ble to represent the data in the more specific property. This is
+ used for things like:
+
+ node1 {
+ compatible = "fred";
+ value = <1>;
+ };
+ node1 {
+ compatible = "fred";
+ value = <1 2>;
+ };
+
+ He we want to use an int array for 'value'. The first property
+ suggests that a single int is enough, but the second one shows that
+ it is not. Calling this function with these two propertes would
+ update the current property to be like the second, since it is less
+ specific.
+ """
+ if self.type.is_wider_than(newprop.type):
+ if self.type == Type.INT and newprop.type == Type.BYTE:
+ if type(self.value) == list:
+ new_value = []
+ for val in self.value:
+ new_value += [chr(by) for by in val]
+ else:
+ new_value = [chr(by) for by in self.value]
+ self.value = new_value
+ self.type = newprop.type
+
+ if type(newprop.value) == list and type(self.value) != list:
+ self.value = [self.value]
+
+ if type(self.value) == list and len(newprop.value) > len(self.value):
+ val = self.GetEmpty(self.type)
+ while len(self.value) < len(newprop.value):
+ self.value.append(val)
+
+ @classmethod
+ def GetEmpty(self, type):
+ """Get an empty / zero value of the given type
+
+ Returns:
+ A single value of the given type
+ """
+ if type == Type.BYTE:
+ return chr(0)
+ elif type == Type.INT:
+ return struct.pack('>I', 0);
+ elif type == Type.STRING:
+ return ''
+ else:
+ return True
+
+ def GetOffset(self):
+ """Get the offset of a property
+
+ Returns:
+ The offset of the property (struct fdt_property) within the file
+ """
+ self._node._fdt.CheckCache()
+ return self._node._fdt.GetStructOffset(self._offset)
+
+ def SetInt(self, val):
+ """Set the integer value of the property
+
+ The device tree is marked dirty so that the value will be written to
+ the block on the next sync.
+
+ Args:
+ val: Integer value (32-bit, single cell)
+ """
+ self.bytes = struct.pack('>I', val);
+ self.value = self.bytes
+ self.type = Type.INT
+ self.dirty = True
+
+ def SetData(self, bytes):
+ """Set the value of a property as bytes
+
+ Args:
+ bytes: New property value to set
+ """
+ self.bytes = bytes
+ self.type, self.value = BytesToValue(bytes)
+ self.dirty = True
+
+ def Sync(self, auto_resize=False):
+ """Sync property changes back to the device tree
+
+ This updates the device tree blob with any changes to this property
+ since the last sync.
+
+ Args:
+ auto_resize: Resize the device tree automatically if it does not
+ have enough space for the update
+
+ Raises:
+ FdtException if auto_resize is False and there is not enough space
+ """
+ if self.dirty:
+ node = self._node
+ fdt_obj = node._fdt._fdt_obj
+ node_name = fdt_obj.get_name(node._offset)
+ if node_name and node_name != node.name:
+ raise ValueError("Internal error, node '%s' name mismatch '%s'" %
+ (node.path, node_name))
+
+ if auto_resize:
+ while fdt_obj.setprop(node.Offset(), self.name, self.bytes,
+ (libfdt.NOSPACE,)) == -libfdt.NOSPACE:
+ fdt_obj.resize(fdt_obj.totalsize() + 1024 +
+ len(self.bytes))
+ fdt_obj.setprop(node.Offset(), self.name, self.bytes)
+ else:
+ fdt_obj.setprop(node.Offset(), self.name, self.bytes)
+ self.dirty = False
+
+
+class Node:
+ """A device tree node
+
+ Properties:
+ parent: Parent Node
+ offset: Integer offset in the device tree (None if to be synced)
+ name: Device tree node tname
+ path: Full path to node, along with the node name itself
+ _fdt: Device tree object
+ subnodes: A list of subnodes for this node, each a Node object
+ props: A dict of properties for this node, each a Prop object.
+ Keyed by property name
+ """
+ def __init__(self, fdt, parent, offset, name, path):
+ self._fdt = fdt
+ self.parent = parent
+ self._offset = offset
+ self.name = name
+ self.path = path
+ self.subnodes = []
+ self.props = {}
+
+ def GetFdt(self):
+ """Get the Fdt object for this node
+
+ Returns:
+ Fdt object
+ """
+ return self._fdt
+
+ def FindNode(self, name):
+ """Find a node given its name
+
+ Args:
+ name: Node name to look for
+ Returns:
+ Node object if found, else None
+ """
+ for subnode in self.subnodes:
+ if subnode.name == name:
+ return subnode
+ return None
+
+ def Offset(self):
+ """Returns the offset of a node, after checking the cache
+
+ This should be used instead of self._offset directly, to ensure that
+ the cache does not contain invalid offsets.
+ """
+ self._fdt.CheckCache()
+ return self._offset
+
+ def Scan(self):
+ """Scan a node's properties and subnodes
+
+ This fills in the props and subnodes properties, recursively
+ searching into subnodes so that the entire tree is built.
+ """
+ fdt_obj = self._fdt._fdt_obj
+ self.props = self._fdt.GetProps(self)
+ phandle = fdt_obj.get_phandle(self.Offset())
+ if phandle:
+ self._fdt.phandle_to_node[phandle] = self
+
+ offset = fdt_obj.first_subnode(self.Offset(), QUIET_NOTFOUND)
+ while offset >= 0:
+ sep = '' if self.path[-1] == '/' else '/'
+ name = fdt_obj.get_name(offset)
+ path = self.path + sep + name
+ node = Node(self._fdt, self, offset, name, path)
+ self.subnodes.append(node)
+
+ node.Scan()
+ offset = fdt_obj.next_subnode(offset, QUIET_NOTFOUND)
+
+ def Refresh(self, my_offset):
+ """Fix up the _offset for each node, recursively
+
+ Note: This does not take account of property offsets - these will not
+ be updated.
+ """
+ fdt_obj = self._fdt._fdt_obj
+ if self._offset != my_offset:
+ self._offset = my_offset
+ name = fdt_obj.get_name(self._offset)
+ if name and self.name != name:
+ raise ValueError("Internal error, node '%s' name mismatch '%s'" %
+ (self.path, name))
+
+ offset = fdt_obj.first_subnode(self._offset, QUIET_NOTFOUND)
+ for subnode in self.subnodes:
+ if subnode.name != fdt_obj.get_name(offset):
+ raise ValueError('Internal error, node name mismatch %s != %s' %
+ (subnode.name, fdt_obj.get_name(offset)))
+ subnode.Refresh(offset)
+ offset = fdt_obj.next_subnode(offset, QUIET_NOTFOUND)
+ if offset != -libfdt.FDT_ERR_NOTFOUND:
+ raise ValueError('Internal error, offset == %d' % offset)
+
+ poffset = fdt_obj.first_property_offset(self._offset, QUIET_NOTFOUND)
+ while poffset >= 0:
+ p = fdt_obj.get_property_by_offset(poffset)
+ prop = self.props.get(p.name)
+ if not prop:
+ raise ValueError("Internal error, node '%s' property '%s' missing, "
+ 'offset %d' % (self.path, p.name, poffset))
+ prop.RefreshOffset(poffset)
+ poffset = fdt_obj.next_property_offset(poffset, QUIET_NOTFOUND)
+
+ def DeleteProp(self, prop_name):
+ """Delete a property of a node
+
+ The property is deleted and the offset cache is invalidated.
+
+ Args:
+ prop_name: Name of the property to delete
+ Raises:
+ ValueError if the property does not exist
+ """
+ CheckErr(self._fdt._fdt_obj.delprop(self.Offset(), prop_name),
+ "Node '%s': delete property: '%s'" % (self.path, prop_name))
+ del self.props[prop_name]
+ self._fdt.Invalidate()
+
+ def AddZeroProp(self, prop_name):
+ """Add a new property to the device tree with an integer value of 0.
+
+ Args:
+ prop_name: Name of property
+ """
+ self.props[prop_name] = Prop(self, None, prop_name,
+ tools.GetBytes(0, 4))
+
+ def AddEmptyProp(self, prop_name, len):
+ """Add a property with a fixed data size, for filling in later
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property
+ len: Length of data in property
+ """
+ value = tools.GetBytes(0, len)
+ self.props[prop_name] = Prop(self, None, prop_name, value)
+
+ def _CheckProp(self, prop_name):
+ """Check if a property is present
+
+ Args:
+ prop_name: Name of property
+
+ Returns:
+ self
+
+ Raises:
+ ValueError if the property is missing
+ """
+ if prop_name not in self.props:
+ raise ValueError("Fdt '%s', node '%s': Missing property '%s'" %
+ (self._fdt._fname, self.path, prop_name))
+ return self
+
+ def SetInt(self, prop_name, val):
+ """Update an integer property int the device tree.
+
+ This is not allowed to change the size of the FDT.
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property
+ val: Value to set
+ """
+ self._CheckProp(prop_name).props[prop_name].SetInt(val)
+
+ def SetData(self, prop_name, val):
+ """Set the data value of a property
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property to set
+ val: Data value to set
+ """
+ self._CheckProp(prop_name).props[prop_name].SetData(val)
+
+ def SetString(self, prop_name, val):
+ """Set the string value of a property
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property to set
+ val: String value to set (will be \0-terminated in DT)
+ """
+ if type(val) == str:
+ val = val.encode('utf-8')
+ self._CheckProp(prop_name).props[prop_name].SetData(val + b'\0')
+
+ def AddData(self, prop_name, val):
+ """Add a new property to a node
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property to add
+ val: Bytes value of property
+
+ Returns:
+ Prop added
+ """
+ prop = Prop(self, None, prop_name, val)
+ self.props[prop_name] = prop
+ return prop
+
+ def AddString(self, prop_name, val):
+ """Add a new string property to a node
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property to add
+ val: String value of property
+
+ Returns:
+ Prop added
+ """
+ val = bytes(val, 'utf-8')
+ return self.AddData(prop_name, val + b'\0')
+
+ def AddInt(self, prop_name, val):
+ """Add a new integer property to a node
+
+ The device tree is marked dirty so that the value will be written to
+ the blob on the next sync.
+
+ Args:
+ prop_name: Name of property to add
+ val: Integer value of property
+
+ Returns:
+ Prop added
+ """
+ return self.AddData(prop_name, struct.pack('>I', val))
+
+ def AddSubnode(self, name):
+ """Add a new subnode to the node
+
+ Args:
+ name: name of node to add
+
+ Returns:
+ New subnode that was created
+ """
+ path = self.path + '/' + name
+ subnode = Node(self._fdt, self, None, name, path)
+ self.subnodes.append(subnode)
+ return subnode
+
+ def Sync(self, auto_resize=False):
+ """Sync node changes back to the device tree
+
+ This updates the device tree blob with any changes to this node and its
+ subnodes since the last sync.
+
+ Args:
+ auto_resize: Resize the device tree automatically if it does not
+ have enough space for the update
+
+ Returns:
+ True if the node had to be added, False if it already existed
+
+ Raises:
+ FdtException if auto_resize is False and there is not enough space
+ """
+ added = False
+ if self._offset is None:
+ # The subnode doesn't exist yet, so add it
+ fdt_obj = self._fdt._fdt_obj
+ if auto_resize:
+ while True:
+ offset = fdt_obj.add_subnode(self.parent._offset, self.name,
+ (libfdt.NOSPACE,))
+ if offset != -libfdt.NOSPACE:
+ break
+ fdt_obj.resize(fdt_obj.totalsize() + 1024)
+ else:
+ offset = fdt_obj.add_subnode(self.parent._offset, self.name)
+ self._offset = offset
+ added = True
+
+ # Sync the existing subnodes first, so that we can rely on the offsets
+ # being correct. As soon as we add new subnodes, it pushes all the
+ # existing subnodes up.
+ for node in reversed(self.subnodes):
+ if node._offset is not None:
+ node.Sync(auto_resize)
+
+ # Sync subnodes in reverse so that we get the expected order. Each
+ # new node goes at the start of the subnode list. This avoids an O(n^2)
+ # rescan of node offsets.
+ num_added = 0
+ for node in reversed(self.subnodes):
+ if node.Sync(auto_resize):
+ num_added += 1
+ if num_added:
+ # Reorder our list of nodes to put the new ones first, since that's
+ # what libfdt does
+ old_count = len(self.subnodes) - num_added
+ subnodes = self.subnodes[old_count:] + self.subnodes[:old_count]
+ self.subnodes = subnodes
+
+ # Sync properties now, whose offsets should not have been disturbed,
+ # since properties come before subnodes. This is done after all the
+ # subnode processing above, since updating properties can disturb the
+ # offsets of those subnodes.
+ # Properties are synced in reverse order, with new properties added
+ # before existing properties are synced. This ensures that the offsets
+ # of earlier properties are not disturbed.
+ # Note that new properties will have an offset of None here, which
+ # Python cannot sort against int. So use a large value instead so that
+ # new properties are added first.
+ prop_list = sorted(self.props.values(),
+ key=lambda prop: prop._offset or 1 << 31,
+ reverse=True)
+ for prop in prop_list:
+ prop.Sync(auto_resize)
+ return added
+
+
+class Fdt:
+ """Provides simple access to a flat device tree blob using libfdts.
+
+ Properties:
+ fname: Filename of fdt
+ _root: Root of device tree (a Node object)
+ name: Helpful name for this Fdt for the user (useful when creating the
+ DT from data rather than a file)
+ """
+ def __init__(self, fname):
+ self._fname = fname
+ self._cached_offsets = False
+ self.phandle_to_node = {}
+ self.name = ''
+ if self._fname:
+ self.name = self._fname
+ self._fname = fdt_util.EnsureCompiled(self._fname)
+
+ with open(self._fname, 'rb') as fd:
+ self._fdt_obj = libfdt.Fdt(fd.read())
+
+ @staticmethod
+ def FromData(data, name=''):
+ """Create a new Fdt object from the given data
+
+ Args:
+ data: Device-tree data blob
+ name: Helpful name for this Fdt for the user
+
+ Returns:
+ Fdt object containing the data
+ """
+ fdt = Fdt(None)
+ fdt._fdt_obj = libfdt.Fdt(bytes(data))
+ fdt.name = name
+ return fdt
+
+ def LookupPhandle(self, phandle):
+ """Look up a phandle
+
+ Args:
+ phandle: Phandle to look up (int)
+
+ Returns:
+ Node object the phandle points to
+ """
+ return self.phandle_to_node.get(phandle)
+
+ def Scan(self, root='/'):
+ """Scan a device tree, building up a tree of Node objects
+
+ This fills in the self._root property
+
+ Args:
+ root: Ignored
+
+ TODO(sjg@chromium.org): Implement the 'root' parameter
+ """
+ self._cached_offsets = True
+ self._root = self.Node(self, None, 0, '/', '/')
+ self._root.Scan()
+
+ def GetRoot(self):
+ """Get the root Node of the device tree
+
+ Returns:
+ The root Node object
+ """
+ return self._root
+
+ def GetNode(self, path):
+ """Look up a node from its path
+
+ Args:
+ path: Path to look up, e.g. '/microcode/update@0'
+ Returns:
+ Node object, or None if not found
+ """
+ node = self._root
+ parts = path.split('/')
+ if len(parts) < 2:
+ return None
+ if len(parts) == 2 and parts[1] == '':
+ return node
+ for part in parts[1:]:
+ node = node.FindNode(part)
+ if not node:
+ return None
+ return node
+
+ def Flush(self):
+ """Flush device tree changes back to the file
+
+ If the device tree has changed in memory, write it back to the file.
+ """
+ with open(self._fname, 'wb') as fd:
+ fd.write(self._fdt_obj.as_bytearray())
+
+ def Sync(self, auto_resize=False):
+ """Make sure any DT changes are written to the blob
+
+ Args:
+ auto_resize: Resize the device tree automatically if it does not
+ have enough space for the update
+
+ Raises:
+ FdtException if auto_resize is False and there is not enough space
+ """
+ self.CheckCache()
+ self._root.Sync(auto_resize)
+ self.Refresh()
+
+ def Pack(self):
+ """Pack the device tree down to its minimum size
+
+ When nodes and properties shrink or are deleted, wasted space can
+ build up in the device tree binary.
+ """
+ CheckErr(self._fdt_obj.pack(), 'pack')
+ self.Refresh()
+
+ def GetContents(self):
+ """Get the contents of the FDT
+
+ Returns:
+ The FDT contents as a string of bytes
+ """
+ return bytes(self._fdt_obj.as_bytearray())
+
+ def GetFdtObj(self):
+ """Get the contents of the FDT
+
+ Returns:
+ The FDT contents as a libfdt.Fdt object
+ """
+ return self._fdt_obj
+
+ def GetProps(self, node):
+ """Get all properties from a node.
+
+ Args:
+ node: Full path to node name to look in.
+
+ Returns:
+ A dictionary containing all the properties, indexed by node name.
+ The entries are Prop objects.
+
+ Raises:
+ ValueError: if the node does not exist.
+ """
+ props_dict = {}
+ poffset = self._fdt_obj.first_property_offset(node._offset,
+ QUIET_NOTFOUND)
+ while poffset >= 0:
+ p = self._fdt_obj.get_property_by_offset(poffset)
+ prop = Prop(node, poffset, p.name, p)
+ props_dict[prop.name] = prop
+
+ poffset = self._fdt_obj.next_property_offset(poffset,
+ QUIET_NOTFOUND)
+ return props_dict
+
+ def Invalidate(self):
+ """Mark our offset cache as invalid"""
+ self._cached_offsets = False
+
+ def CheckCache(self):
+ """Refresh the offset cache if needed"""
+ if self._cached_offsets:
+ return
+ self.Refresh()
+
+ def Refresh(self):
+ """Refresh the offset cache"""
+ self._root.Refresh(0)
+ self._cached_offsets = True
+
+ def GetStructOffset(self, offset):
+ """Get the file offset of a given struct offset
+
+ Args:
+ offset: Offset within the 'struct' region of the device tree
+ Returns:
+ Position of @offset within the device tree binary
+ """
+ return self._fdt_obj.off_dt_struct() + offset
+
+ @classmethod
+ def Node(self, fdt, parent, offset, name, path):
+ """Create a new node
+
+ This is used by Fdt.Scan() to create a new node using the correct
+ class.
+
+ Args:
+ fdt: Fdt object
+ parent: Parent node, or None if this is the root node
+ offset: Offset of node
+ name: Node name
+ path: Full path to node
+ """
+ node = Node(fdt, parent, offset, name, path)
+ return node
+
+ def GetFilename(self):
+ """Get the filename of the device tree
+
+ Returns:
+ String filename
+ """
+ return self._fname
+
+def FdtScan(fname):
+ """Returns a new Fdt object"""
+ dtb = Fdt(fname)
+ dtb.Scan()
+ return dtb
diff --git a/roms/u-boot/tools/dtoc/fdt_util.py b/roms/u-boot/tools/dtoc/fdt_util.py
new file mode 100644
index 000000000..37e96b986
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/fdt_util.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+# Utility functions for reading from a device tree. Once the upstream pylibfdt
+# implementation advances far enough, we should be able to drop these.
+
+import os
+import struct
+import sys
+import tempfile
+
+from patman import command
+from patman import tools
+
+def fdt32_to_cpu(val):
+ """Convert a device tree cell to an integer
+
+ Args:
+ Value to convert (4-character string representing the cell value)
+
+ Return:
+ A native-endian integer value
+ """
+ return struct.unpack('>I', val)[0]
+
+def fdt_cells_to_cpu(val, cells):
+ """Convert one or two cells to a long integer
+
+ Args:
+ Value to convert (array of one or more 4-character strings)
+
+ Return:
+ A native-endian integer value
+ """
+ if not cells:
+ return 0
+ out = int(fdt32_to_cpu(val[0]))
+ if cells == 2:
+ out = out << 32 | fdt32_to_cpu(val[1])
+ return out
+
+def EnsureCompiled(fname, tmpdir=None, capture_stderr=False):
+ """Compile an fdt .dts source file into a .dtb binary blob if needed.
+
+ Args:
+ fname: Filename (if .dts it will be compiled). It not it will be
+ left alone
+ tmpdir: Temporary directory for output files, or None to use the
+ tools-module output directory
+
+ Returns:
+ Filename of resulting .dtb file
+ """
+ _, ext = os.path.splitext(fname)
+ if ext != '.dts':
+ return fname
+
+ if tmpdir:
+ dts_input = os.path.join(tmpdir, 'source.dts')
+ dtb_output = os.path.join(tmpdir, 'source.dtb')
+ else:
+ dts_input = tools.GetOutputFilename('source.dts')
+ dtb_output = tools.GetOutputFilename('source.dtb')
+
+ search_paths = [os.path.join(os.getcwd(), 'include')]
+ root, _ = os.path.splitext(fname)
+ cc, args = tools.GetTargetCompileTool('cc')
+ args += ['-E', '-P', '-x', 'assembler-with-cpp', '-D__ASSEMBLY__']
+ args += ['-Ulinux']
+ for path in search_paths:
+ args.extend(['-I', path])
+ args += ['-o', dts_input, fname]
+ command.Run(cc, *args)
+
+ # If we don't have a directory, put it in the tools tempdir
+ search_list = []
+ for path in search_paths:
+ search_list.extend(['-i', path])
+ dtc, args = tools.GetTargetCompileTool('dtc')
+ args += ['-I', 'dts', '-o', dtb_output, '-O', 'dtb',
+ '-W', 'no-unit_address_vs_reg']
+ args.extend(search_list)
+ args.append(dts_input)
+ command.Run(dtc, *args, capture_stderr=capture_stderr)
+ return dtb_output
+
+def GetInt(node, propname, default=None):
+ """Get an integer from a property
+
+ Args:
+ node: Node object to read from
+ propname: property name to read
+ default: Default value to use if the node/property do not exist
+
+ Returns:
+ Integer value read, or default if none
+ """
+ prop = node.props.get(propname)
+ if not prop:
+ return default
+ if isinstance(prop.value, list):
+ raise ValueError("Node '%s' property '%s' has list value: expecting "
+ "a single integer" % (node.name, propname))
+ value = fdt32_to_cpu(prop.value)
+ return value
+
+def GetString(node, propname, default=None):
+ """Get a string from a property
+
+ Args:
+ node: Node object to read from
+ propname: property name to read
+ default: Default value to use if the node/property do not exist
+
+ Returns:
+ String value read, or default if none
+ """
+ prop = node.props.get(propname)
+ if not prop:
+ return default
+ value = prop.value
+ if isinstance(value, list):
+ raise ValueError("Node '%s' property '%s' has list value: expecting "
+ "a single string" % (node.name, propname))
+ return value
+
+def GetBool(node, propname, default=False):
+ """Get an boolean from a property
+
+ Args:
+ node: Node object to read from
+ propname: property name to read
+ default: Default value to use if the node/property do not exist
+
+ Returns:
+ Boolean value read, or default if none (if you set this to True the
+ function will always return True)
+ """
+ if propname in node.props:
+ return True
+ return default
+
+def GetByte(node, propname, default=None):
+ """Get an byte from a property
+
+ Args:
+ node: Node object to read from
+ propname: property name to read
+ default: Default value to use if the node/property do not exist
+
+ Returns:
+ Byte value read, or default if none
+ """
+ prop = node.props.get(propname)
+ if not prop:
+ return default
+ value = prop.value
+ if isinstance(value, list):
+ raise ValueError("Node '%s' property '%s' has list value: expecting "
+ "a single byte" % (node.name, propname))
+ if len(value) != 1:
+ raise ValueError("Node '%s' property '%s' has length %d, expecting %d" %
+ (node.name, propname, len(value), 1))
+ return ord(value[0])
+
+def GetPhandleList(node, propname):
+ """Get a list of phandles from a property
+
+ Args:
+ node: Node object to read from
+ propname: property name to read
+
+ Returns:
+ List of phandles read, each an integer
+ """
+ prop = node.props.get(propname)
+ if not prop:
+ return None
+ value = prop.value
+ if not isinstance(value, list):
+ value = [value]
+ return [fdt32_to_cpu(v) for v in value]
+
+def GetDatatype(node, propname, datatype):
+ """Get a value of a given type from a property
+
+ Args:
+ node: Node object to read from
+ propname: property name to read
+ datatype: Type to read (str or int)
+
+ Returns:
+ value read, or None if none
+
+ Raises:
+ ValueError if datatype is not str or int
+ """
+ if datatype == str:
+ return GetString(node, propname)
+ elif datatype == int:
+ return GetInt(node, propname)
+ raise ValueError("fdt_util internal error: Unknown data type '%s'" %
+ datatype)
diff --git a/roms/u-boot/tools/dtoc/main.py b/roms/u-boot/tools/dtoc/main.py
new file mode 100755
index 000000000..93706de89
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/main.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+"""Device tree to C tool
+
+This tool converts a device tree binary file (.dtb) into two C files. The
+indent is to allow a C program to access data from the device tree without
+having to link against libfdt. By putting the data from the device tree into
+C structures, normal C code can be used. This helps to reduce the size of the
+compiled program.
+
+Dtoc produces several output files - see OUTPUT_FILES in dtb_platdata.py
+
+This tool is used in U-Boot to provide device tree data to SPL without
+increasing the code size of SPL. This supports the CONFIG_SPL_OF_PLATDATA
+options. For more information about the use of this options and tool please
+see doc/driver-model/of-plat.rst
+"""
+
+from optparse import OptionParser
+import os
+import sys
+import unittest
+
+# Bring in the patman libraries
+our_path = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(our_path, '..'))
+
+# Bring in the libfdt module
+sys.path.insert(0, 'scripts/dtc/pylibfdt')
+sys.path.insert(0, os.path.join(our_path,
+ '../../build-sandbox_spl/scripts/dtc/pylibfdt'))
+
+from dtoc import dtb_platdata
+from patman import test_util
+
+def run_tests(processes, args):
+ """Run all the test we have for dtoc
+
+ Args:
+ processes: Number of processes to use to run tests (None=same as #CPUs)
+ args: List of positional args provided to dtoc. This can hold a test
+ name to execute (as in 'dtoc -t test_empty_file', for example)
+ """
+ from dtoc import test_src_scan
+ from dtoc import test_dtoc
+
+ result = unittest.TestResult()
+ sys.argv = [sys.argv[0]]
+ test_name = args and args[0] or None
+
+ test_dtoc.setup()
+
+ test_util.RunTestSuites(
+ result, debug=True, verbosity=1, test_preserve_dirs=False,
+ processes=processes, test_name=test_name, toolpath=[],
+ test_class_list=[test_dtoc.TestDtoc,test_src_scan.TestSrcScan])
+
+ return test_util.ReportResult('binman', test_name, result)
+
+def RunTestCoverage():
+ """Run the tests and check that we get 100% coverage"""
+ sys.argv = [sys.argv[0]]
+ test_util.RunTestCoverage('tools/dtoc/dtoc', '/main.py',
+ ['tools/patman/*.py', '*/fdt*', '*test*'], options.build_dir)
+
+
+if __name__ != '__main__':
+ sys.exit(1)
+
+parser = OptionParser()
+parser.add_option('-B', '--build-dir', type='string', default='b',
+ help='Directory containing the build output')
+parser.add_option('-c', '--c-output-dir', action='store',
+ help='Select output directory for C files')
+parser.add_option('-C', '--h-output-dir', action='store',
+ help='Select output directory for H files (defaults to --c-output-di)')
+parser.add_option('-d', '--dtb-file', action='store',
+ help='Specify the .dtb input file')
+parser.add_option('-i', '--instantiate', action='store_true', default=False,
+ help='Instantiate devices to avoid needing device_bind()')
+parser.add_option('--include-disabled', action='store_true',
+ help='Include disabled nodes')
+parser.add_option('-o', '--output', action='store',
+ help='Select output filename')
+parser.add_option('-p', '--phase', type=str,
+ help='set phase of U-Boot this invocation is for (spl/tpl)')
+parser.add_option('-P', '--processes', type=int,
+ help='set number of processes to use for running tests')
+parser.add_option('-t', '--test', action='store_true', dest='test',
+ default=False, help='run tests')
+parser.add_option('-T', '--test-coverage', action='store_true',
+ default=False, help='run tests and check for 100% coverage')
+(options, args) = parser.parse_args()
+
+# Run our meagre tests
+if options.test:
+ ret_code = run_tests(options.processes, args)
+ sys.exit(ret_code)
+
+elif options.test_coverage:
+ RunTestCoverage()
+
+else:
+ dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled,
+ options.output,
+ [options.c_output_dir, options.h_output_dir],
+ options.phase, instantiate=options.instantiate)
diff --git a/roms/u-boot/tools/dtoc/setup.py b/roms/u-boot/tools/dtoc/setup.py
new file mode 100644
index 000000000..5e092fe08
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/setup.py
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+from distutils.core import setup
+setup(name='dtoc',
+ version='1.0',
+ license='GPL-2.0+',
+ scripts=['dtoc'],
+ packages=['dtoc'],
+ package_dir={'dtoc': ''},
+ package_data={'dtoc': ['README']},
+ classifiers=['Environment :: Console',
+ 'Topic :: Software Development :: Embedded Systems'])
diff --git a/roms/u-boot/tools/dtoc/src_scan.py b/roms/u-boot/tools/dtoc/src_scan.py
new file mode 100644
index 000000000..2db96884c
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/src_scan.py
@@ -0,0 +1,739 @@
+#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2017 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+"""Scanning of U-Boot source for drivers and structs
+
+This scans the source tree to find out things about all instances of
+U_BOOT_DRIVER(), UCLASS_DRIVER and all struct declarations in header files.
+
+See doc/driver-model/of-plat.rst for more informaiton
+"""
+
+import os
+import re
+import sys
+
+
+def conv_name_to_c(name):
+ """Convert a device-tree name to a C identifier
+
+ This uses multiple replace() calls instead of re.sub() since it is faster
+ (400ms for 1m calls versus 1000ms for the 're' version).
+
+ Args:
+ name (str): Name to convert
+ Return:
+ str: String containing the C version of this name
+ """
+ new = name.replace('@', '_at_')
+ new = new.replace('-', '_')
+ new = new.replace(',', '_')
+ new = new.replace('.', '_')
+ if new == '/':
+ return 'root'
+ return new
+
+def get_compat_name(node):
+ """Get the node's list of compatible string as a C identifiers
+
+ Args:
+ node (fdt.Node): Node object to check
+ Return:
+ list of str: List of C identifiers for all the compatible strings
+ """
+ compat = node.props['compatible'].value
+ if not isinstance(compat, list):
+ compat = [compat]
+ return [conv_name_to_c(c) for c in compat]
+
+
+class Driver:
+ """Information about a driver in U-Boot
+
+ Attributes:
+ name: Name of driver. For U_BOOT_DRIVER(x) this is 'x'
+ fname: Filename where the driver was found
+ uclass_id: Name of uclass, e.g. 'UCLASS_I2C'
+ compat: Driver data for each compatible string:
+ key: Compatible string, e.g. 'rockchip,rk3288-grf'
+ value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+ fname: Filename where the driver was found
+ priv (str): struct name of the priv_auto member, e.g. 'serial_priv'
+ plat (str): struct name of the plat_auto member, e.g. 'serial_plat'
+ child_priv (str): struct name of the per_child_auto member,
+ e.g. 'pci_child_priv'
+ child_plat (str): struct name of the per_child_plat_auto member,
+ e.g. 'pci_child_plat'
+ used (bool): True if the driver is used by the structs being output
+ phase (str): Which phase of U-Boot to use this driver
+ headers (list): List of header files needed for this driver (each a str)
+ e.g. ['<asm/cpu.h>']
+ dups (list): Driver objects with the same name as this one, that were
+ found after this one
+ warn_dups (bool): True if the duplicates are not distinguisble using
+ the phase
+ uclass (Uclass): uclass for this driver
+ """
+ def __init__(self, name, fname):
+ self.name = name
+ self.fname = fname
+ self.uclass_id = None
+ self.compat = None
+ self.priv = ''
+ self.plat = ''
+ self.child_priv = ''
+ self.child_plat = ''
+ self.used = False
+ self.phase = ''
+ self.headers = []
+ self.dups = []
+ self.warn_dups = False
+ self.uclass = None
+
+ def __eq__(self, other):
+ return (self.name == other.name and
+ self.uclass_id == other.uclass_id and
+ self.compat == other.compat and
+ self.priv == other.priv and
+ self.plat == other.plat and
+ self.used == other.used)
+
+ def __repr__(self):
+ return ("Driver(name='%s', used=%s, uclass_id='%s', compat=%s, priv=%s)" %
+ (self.name, self.used, self.uclass_id, self.compat, self.priv))
+
+
+class UclassDriver:
+ """Holds information about a uclass driver
+
+ Attributes:
+ name: Uclass name, e.g. 'i2c' if the driver is for UCLASS_I2C
+ uclass_id: Uclass ID, e.g. 'UCLASS_I2C'
+ priv: struct name of the private data, e.g. 'i2c_priv'
+ per_dev_priv (str): struct name of the priv_auto member, e.g. 'spi_info'
+ per_dev_plat (str): struct name of the plat_auto member, e.g. 'i2c_chip'
+ per_child_priv (str): struct name of the per_child_auto member,
+ e.g. 'pci_child_priv'
+ per_child_plat (str): struct name of the per_child_plat_auto member,
+ e.g. 'pci_child_plat'
+ alias_num_to_node (dict): Aliases for this uclasses (for sequence
+ numbers)
+ key (int): Alias number, e.g. 2 for "pci2"
+ value (str): Node the alias points to
+ alias_path_to_num (dict): Convert a path to an alias number
+ key (str): Full path to node (e.g. '/soc/pci')
+ seq (int): Alias number, e.g. 2 for "pci2"
+ devs (list): List of devices in this uclass, each a Node
+ node_refs (dict): References in the linked list of devices:
+ key (int): Sequence number (0=first, n-1=last, -1=head, n=tail)
+ value (str): Reference to the device at that position
+ """
+ def __init__(self, name):
+ self.name = name
+ self.uclass_id = None
+ self.priv = ''
+ self.per_dev_priv = ''
+ self.per_dev_plat = ''
+ self.per_child_priv = ''
+ self.per_child_plat = ''
+ self.alias_num_to_node = {}
+ self.alias_path_to_num = {}
+ self.devs = []
+ self.node_refs = {}
+
+ def __eq__(self, other):
+ return (self.name == other.name and
+ self.uclass_id == other.uclass_id and
+ self.priv == other.priv)
+
+ def __repr__(self):
+ return ("UclassDriver(name='%s', uclass_id='%s')" %
+ (self.name, self.uclass_id))
+
+ def __hash__(self):
+ # We can use the uclass ID since it is unique among uclasses
+ return hash(self.uclass_id)
+
+
+class Struct:
+ """Holds information about a struct definition
+
+ Attributes:
+ name: Struct name, e.g. 'fred' if the struct is 'struct fred'
+ fname: Filename containing the struct, in a format that C files can
+ include, e.g. 'asm/clk.h'
+ """
+ def __init__(self, name, fname):
+ self.name = name
+ self.fname =fname
+
+ def __repr__(self):
+ return ("Struct(name='%s', fname='%s')" % (self.name, self.fname))
+
+
+class Scanner:
+ """Scanning of the U-Boot source tree
+
+ Properties:
+ _basedir (str): Base directory of U-Boot source code. Defaults to the
+ grandparent of this file's directory
+ _drivers: Dict of valid driver names found in drivers/
+ key: Driver name
+ value: Driver for that driver
+ _driver_aliases: Dict that holds aliases for driver names
+ key: Driver alias declared with
+ DM_DRIVER_ALIAS(driver_alias, driver_name)
+ value: Driver name declared with U_BOOT_DRIVER(driver_name)
+ _drivers_additional (list or str): List of additional drivers to use
+ during scanning
+ _of_match: Dict holding information about compatible strings
+ key: Name of struct udevice_id variable
+ value: Dict of compatible info in that variable:
+ key: Compatible string, e.g. 'rockchip,rk3288-grf'
+ value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+ _compat_to_driver: Maps compatible strings to Driver
+ _uclass: Dict of uclass information
+ key: uclass name, e.g. 'UCLASS_I2C'
+ value: UClassDriver
+ _structs: Dict of all structs found in U-Boot:
+ key: Name of struct
+ value: Struct object
+ _phase: The phase of U-Boot that we are generating data for, e.g. 'spl'
+ or 'tpl'. None if not known
+ """
+ def __init__(self, basedir, drivers_additional, phase=''):
+ """Set up a new Scanner
+ """
+ if not basedir:
+ basedir = sys.argv[0].replace('tools/dtoc/dtoc', '')
+ if basedir == '':
+ basedir = './'
+ self._basedir = basedir
+ self._drivers = {}
+ self._driver_aliases = {}
+ self._drivers_additional = drivers_additional or []
+ self._missing_drivers = set()
+ self._of_match = {}
+ self._compat_to_driver = {}
+ self._uclass = {}
+ self._structs = {}
+ self._phase = phase
+
+ def get_driver(self, name):
+ """Get a driver given its name
+
+ Args:
+ name (str): Driver name
+
+ Returns:
+ Driver: Driver or None if not found
+ """
+ return self._drivers.get(name)
+
+ def get_normalized_compat_name(self, node):
+ """Get a node's normalized compat name
+
+ Returns a valid driver name by retrieving node's list of compatible
+ string as a C identifier and performing a check against _drivers
+ and a lookup in driver_aliases printing a warning in case of failure.
+
+ Args:
+ node (Node): Node object to check
+ Return:
+ Tuple:
+ Driver name associated with the first compatible string
+ List of C identifiers for all the other compatible strings
+ (possibly empty)
+ In case of no match found, the return will be the same as
+ get_compat_name()
+ """
+ if not node.parent:
+ compat_list_c = ['root_driver']
+ else:
+ compat_list_c = get_compat_name(node)
+
+ for compat_c in compat_list_c:
+ if not compat_c in self._drivers.keys():
+ compat_c = self._driver_aliases.get(compat_c)
+ if not compat_c:
+ continue
+
+ aliases_c = compat_list_c
+ if compat_c in aliases_c:
+ aliases_c.remove(compat_c)
+ return compat_c, aliases_c
+
+ self._missing_drivers.add(compat_list_c[0])
+
+ return compat_list_c[0], compat_list_c[1:]
+
+ def _parse_structs(self, fname, buff):
+ """Parse a H file to extract struct definitions contained within
+
+ This parses 'struct xx {' definitions to figure out what structs this
+ header defines.
+
+ Args:
+ buff (str): Contents of file
+ fname (str): Filename (to use when printing errors)
+ """
+ structs = {}
+
+ re_struct = re.compile('^struct ([a-z0-9_]+) {$')
+ re_asm = re.compile('../arch/[a-z0-9]+/include/asm/(.*)')
+ prefix = ''
+ for line in buff.splitlines():
+ # Handle line continuation
+ if prefix:
+ line = prefix + line
+ prefix = ''
+ if line.endswith('\\'):
+ prefix = line[:-1]
+ continue
+
+ m_struct = re_struct.match(line)
+ if m_struct:
+ name = m_struct.group(1)
+ include_dir = os.path.join(self._basedir, 'include')
+ rel_fname = os.path.relpath(fname, include_dir)
+ m_asm = re_asm.match(rel_fname)
+ if m_asm:
+ rel_fname = 'asm/' + m_asm.group(1)
+ structs[name] = Struct(name, rel_fname)
+ self._structs.update(structs)
+
+ @classmethod
+ def _get_re_for_member(cls, member):
+ """_get_re_for_member: Get a compiled regular expression
+
+ Args:
+ member (str): Struct member name, e.g. 'priv_auto'
+
+ Returns:
+ re.Pattern: Compiled regular expression that parses:
+
+ .member = sizeof(struct fred),
+
+ and returns "fred" as group 1
+ """
+ return re.compile(r'^\s*.%s\s*=\s*sizeof\(struct\s+(.*)\),$' % member)
+
+ def _parse_uclass_driver(self, fname, buff):
+ """Parse a C file to extract uclass driver information contained within
+
+ This parses UCLASS_DRIVER() structs to obtain various pieces of useful
+ information.
+
+ It updates the following member:
+ _uclass: Dict of uclass information
+ key: uclass name, e.g. 'UCLASS_I2C'
+ value: UClassDriver
+
+ Args:
+ fname (str): Filename being parsed (used for warnings)
+ buff (str): Contents of file
+ """
+ uc_drivers = {}
+
+ # Collect the driver name and associated Driver
+ driver = None
+ re_driver = re.compile(r'^UCLASS_DRIVER\((.*)\)')
+
+ # Collect the uclass ID, e.g. 'UCLASS_SPI'
+ re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
+
+ # Matches the header/size information for uclass-private data
+ re_priv = self._get_re_for_member('priv_auto')
+
+ # Set up parsing for the auto members
+ re_per_device_priv = self._get_re_for_member('per_device_auto')
+ re_per_device_plat = self._get_re_for_member('per_device_plat_auto')
+ re_per_child_priv = self._get_re_for_member('per_child_auto')
+ re_per_child_plat = self._get_re_for_member('per_child_plat_auto')
+
+ prefix = ''
+ for line in buff.splitlines():
+ # Handle line continuation
+ if prefix:
+ line = prefix + line
+ prefix = ''
+ if line.endswith('\\'):
+ prefix = line[:-1]
+ continue
+
+ driver_match = re_driver.search(line)
+
+ # If we have seen UCLASS_DRIVER()...
+ if driver:
+ m_id = re_id.search(line)
+ m_priv = re_priv.match(line)
+ m_per_dev_priv = re_per_device_priv.match(line)
+ m_per_dev_plat = re_per_device_plat.match(line)
+ m_per_child_priv = re_per_child_priv.match(line)
+ m_per_child_plat = re_per_child_plat.match(line)
+ if m_id:
+ driver.uclass_id = m_id.group(1)
+ elif m_priv:
+ driver.priv = m_priv.group(1)
+ elif m_per_dev_priv:
+ driver.per_dev_priv = m_per_dev_priv.group(1)
+ elif m_per_dev_plat:
+ driver.per_dev_plat = m_per_dev_plat.group(1)
+ elif m_per_child_priv:
+ driver.per_child_priv = m_per_child_priv.group(1)
+ elif m_per_child_plat:
+ driver.per_child_plat = m_per_child_plat.group(1)
+ elif '};' in line:
+ if not driver.uclass_id:
+ raise ValueError(
+ "%s: Cannot parse uclass ID in driver '%s'" %
+ (fname, driver.name))
+ uc_drivers[driver.uclass_id] = driver
+ driver = None
+
+ elif driver_match:
+ driver_name = driver_match.group(1)
+ driver = UclassDriver(driver_name)
+
+ self._uclass.update(uc_drivers)
+
+ def _parse_driver(self, fname, buff):
+ """Parse a C file to extract driver information contained within
+
+ This parses U_BOOT_DRIVER() structs to obtain various pieces of useful
+ information.
+
+ It updates the following members:
+ _drivers - updated with new Driver records for each driver found
+ in the file
+ _of_match - updated with each compatible string found in the file
+ _compat_to_driver - Maps compatible string to Driver
+ _driver_aliases - Maps alias names to driver name
+
+ Args:
+ fname (str): Filename being parsed (used for warnings)
+ buff (str): Contents of file
+
+ Raises:
+ ValueError: Compatible variable is mentioned in .of_match in
+ U_BOOT_DRIVER() but not found in the file
+ """
+ # Dict holding information about compatible strings collected in this
+ # function so far
+ # key: Name of struct udevice_id variable
+ # value: Dict of compatible info in that variable:
+ # key: Compatible string, e.g. 'rockchip,rk3288-grf'
+ # value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+ of_match = {}
+
+ # Dict holding driver information collected in this function so far
+ # key: Driver name (C name as in U_BOOT_DRIVER(xxx))
+ # value: Driver
+ drivers = {}
+
+ # Collect the driver info
+ driver = None
+ re_driver = re.compile(r'^U_BOOT_DRIVER\((.*)\)')
+
+ # Collect the uclass ID, e.g. 'UCLASS_SPI'
+ re_id = re.compile(r'\s*\.id\s*=\s*(UCLASS_[A-Z0-9_]+)')
+
+ # Collect the compatible string, e.g. 'rockchip,rk3288-grf'
+ compat = None
+ re_compat = re.compile(r'{\s*.compatible\s*=\s*"(.*)"\s*'
+ r'(,\s*.data\s*=\s*(\S*))?\s*},')
+
+ # This is a dict of compatible strings that were found:
+ # key: Compatible string, e.g. 'rockchip,rk3288-grf'
+ # value: Driver data, e,g, 'ROCKCHIP_SYSCON_GRF', or None
+ compat_dict = {}
+
+ # Holds the var nane of the udevice_id list, e.g.
+ # 'rk3288_syscon_ids_noc' in
+ # static const struct udevice_id rk3288_syscon_ids_noc[] = {
+ ids_name = None
+ re_ids = re.compile(r'struct udevice_id (.*)\[\]\s*=')
+
+ # Matches the references to the udevice_id list
+ re_of_match = re.compile(
+ r'\.of_match\s*=\s*(of_match_ptr\()?([a-z0-9_]+)(\))?,')
+
+ re_phase = re.compile('^\s*DM_PHASE\((.*)\).*$')
+ re_hdr = re.compile('^\s*DM_HEADER\((.*)\).*$')
+ re_alias = re.compile(r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)')
+
+ # Matches the struct name for priv, plat
+ re_priv = self._get_re_for_member('priv_auto')
+ re_plat = self._get_re_for_member('plat_auto')
+ re_child_priv = self._get_re_for_member('per_child_auto')
+ re_child_plat = self._get_re_for_member('per_child_plat_auto')
+
+ prefix = ''
+ for line in buff.splitlines():
+ # Handle line continuation
+ if prefix:
+ line = prefix + line
+ prefix = ''
+ if line.endswith('\\'):
+ prefix = line[:-1]
+ continue
+
+ driver_match = re_driver.search(line)
+
+ # If this line contains U_BOOT_DRIVER()...
+ if driver:
+ m_id = re_id.search(line)
+ m_of_match = re_of_match.search(line)
+ m_priv = re_priv.match(line)
+ m_plat = re_plat.match(line)
+ m_cplat = re_child_plat.match(line)
+ m_cpriv = re_child_priv.match(line)
+ m_phase = re_phase.match(line)
+ m_hdr = re_hdr.match(line)
+ if m_priv:
+ driver.priv = m_priv.group(1)
+ elif m_plat:
+ driver.plat = m_plat.group(1)
+ elif m_cplat:
+ driver.child_plat = m_cplat.group(1)
+ elif m_cpriv:
+ driver.child_priv = m_cpriv.group(1)
+ elif m_id:
+ driver.uclass_id = m_id.group(1)
+ elif m_of_match:
+ compat = m_of_match.group(2)
+ elif m_phase:
+ driver.phase = m_phase.group(1)
+ elif m_hdr:
+ driver.headers.append(m_hdr.group(1))
+ elif '};' in line:
+ is_root = driver.name == 'root_driver'
+ if driver.uclass_id and (compat or is_root):
+ if not is_root:
+ if compat not in of_match:
+ raise ValueError(
+ "%s: Unknown compatible var '%s' (found: %s)" %
+ (fname, compat, ','.join(of_match.keys())))
+ driver.compat = of_match[compat]
+
+ # This needs to be deterministic, since a driver may
+ # have multiple compatible strings pointing to it.
+ # We record the one earliest in the alphabet so it
+ # will produce the same result on all machines.
+ for compat_id in of_match[compat]:
+ old = self._compat_to_driver.get(compat_id)
+ if not old or driver.name < old.name:
+ self._compat_to_driver[compat_id] = driver
+ drivers[driver.name] = driver
+ else:
+ # The driver does not have a uclass or compat string.
+ # The first is required but the second is not, so just
+ # ignore this.
+ pass
+ driver = None
+ ids_name = None
+ compat = None
+ compat_dict = {}
+
+ elif ids_name:
+ compat_m = re_compat.search(line)
+ if compat_m:
+ compat_dict[compat_m.group(1)] = compat_m.group(3)
+ elif '};' in line:
+ of_match[ids_name] = compat_dict
+ ids_name = None
+ elif driver_match:
+ driver_name = driver_match.group(1)
+ driver = Driver(driver_name, fname)
+ else:
+ ids_m = re_ids.search(line)
+ m_alias = re_alias.match(line)
+ if ids_m:
+ ids_name = ids_m.group(1)
+ elif m_alias:
+ self._driver_aliases[m_alias[2]] = m_alias[1]
+
+ # Make the updates based on what we found
+ for driver in drivers.values():
+ if driver.name in self._drivers:
+ orig = self._drivers[driver.name]
+ if self._phase:
+ # If the original driver matches our phase, use it
+ if orig.phase == self._phase:
+ orig.dups.append(driver)
+ continue
+
+ # Otherwise use the new driver, which is assumed to match
+ else:
+ # We have no way of distinguishing them
+ driver.warn_dups = True
+ driver.dups.append(orig)
+ self._drivers[driver.name] = driver
+ self._of_match.update(of_match)
+
+ def show_warnings(self):
+ """Show any warnings that have been collected"""
+ for name in sorted(list(self._missing_drivers)):
+ print('WARNING: the driver %s was not found in the driver list'
+ % name)
+
+ def scan_driver(self, fname):
+ """Scan a driver file to build a list of driver names and aliases
+
+ It updates the following members:
+ _drivers - updated with new Driver records for each driver found
+ in the file
+ _of_match - updated with each compatible string found in the file
+ _compat_to_driver - Maps compatible string to Driver
+ _driver_aliases - Maps alias names to driver name
+
+ Args
+ fname: Driver filename to scan
+ """
+ with open(fname, encoding='utf-8') as inf:
+ try:
+ buff = inf.read()
+ except UnicodeDecodeError:
+ # This seems to happen on older Python versions
+ print("Skipping file '%s' due to unicode error" % fname)
+ return
+
+ # If this file has any U_BOOT_DRIVER() declarations, process it to
+ # obtain driver information
+ if 'U_BOOT_DRIVER' in buff:
+ self._parse_driver(fname, buff)
+ if 'UCLASS_DRIVER' in buff:
+ self._parse_uclass_driver(fname, buff)
+
+ def scan_header(self, fname):
+ """Scan a header file to build a list of struct definitions
+
+ It updates the following members:
+ _structs - updated with new Struct records for each struct found
+ in the file
+
+ Args
+ fname: header filename to scan
+ """
+ with open(fname, encoding='utf-8') as inf:
+ try:
+ buff = inf.read()
+ except UnicodeDecodeError:
+ # This seems to happen on older Python versions
+ print("Skipping file '%s' due to unicode error" % fname)
+ return
+
+ # If this file has any U_BOOT_DRIVER() declarations, process it to
+ # obtain driver information
+ if 'struct' in buff:
+ self._parse_structs(fname, buff)
+
+ def scan_drivers(self):
+ """Scan the driver folders to build a list of driver names and aliases
+
+ This procedure will populate self._drivers and self._driver_aliases
+ """
+ for (dirpath, _, filenames) in os.walk(self._basedir):
+ rel_path = dirpath[len(self._basedir):]
+ if rel_path.startswith('/'):
+ rel_path = rel_path[1:]
+ if rel_path.startswith('build') or rel_path.startswith('.git'):
+ continue
+ for fname in filenames:
+ pathname = dirpath + '/' + fname
+ if fname.endswith('.c'):
+ self.scan_driver(pathname)
+ elif fname.endswith('.h'):
+ self.scan_header(pathname)
+ for fname in self._drivers_additional:
+ if not isinstance(fname, str) or len(fname) == 0:
+ continue
+ if fname[0] == '/':
+ self.scan_driver(fname)
+ else:
+ self.scan_driver(self._basedir + '/' + fname)
+
+ # Get the uclass for each driver
+ # TODO: Can we just get the uclass for the ones we use, e.g. in
+ # mark_used()?
+ for driver in self._drivers.values():
+ driver.uclass = self._uclass.get(driver.uclass_id)
+
+ def mark_used(self, nodes):
+ """Mark the drivers associated with a list of nodes as 'used'
+
+ This takes a list of nodes, finds the driver for each one and marks it
+ as used.
+
+ If two used drivers have the same name, issue a warning.
+
+ Args:
+ nodes (list of None): Nodes that are in use
+ """
+ # Figure out which drivers we actually use
+ for node in nodes:
+ struct_name, _ = self.get_normalized_compat_name(node)
+ driver = self._drivers.get(struct_name)
+ if driver:
+ driver.used = True
+ if driver.dups and driver.warn_dups:
+ print("Warning: Duplicate driver name '%s' (orig=%s, dups=%s)" %
+ (driver.name, driver.fname,
+ ', '.join([drv.fname for drv in driver.dups])))
+
+ def add_uclass_alias(self, name, num, node):
+ """Add an alias to a uclass
+
+ Args:
+ name: Name of uclass, e.g. 'i2c'
+ num: Alias number, e.g. 2 for alias 'i2c2'
+ node: Node the alias points to, or None if None
+
+ Returns:
+ True if the node was added
+ False if the node was not added (uclass of that name not found)
+ None if the node could not be added because it was None
+ """
+ for uclass in self._uclass.values():
+ if uclass.name == name:
+ if node is None:
+ return None
+ uclass.alias_num_to_node[int(num)] = node
+ uclass.alias_path_to_num[node.path] = int(num)
+ return True
+ return False
+
+ def assign_seq(self, node):
+ """Figure out the sequence number for a node
+
+ This looks in the node's uclass and assigns a sequence number if needed,
+ based on the aliases and other nodes in that uclass.
+
+ It updates the uclass alias_path_to_num and alias_num_to_node
+
+ Args:
+ node (Node): Node object to look up
+ """
+ if node.driver and node.seq == -1 and node.uclass:
+ uclass = node.uclass
+ num = uclass.alias_path_to_num.get(node.path)
+ if num is not None:
+ return num
+ else:
+ # Dynamically allocate the next available value after all
+ # existing ones
+ if uclass.alias_num_to_node:
+ start = max(uclass.alias_num_to_node.keys())
+ else:
+ start = -1
+ for seq in range(start + 1, 1000):
+ if seq not in uclass.alias_num_to_node:
+ break
+ uclass.alias_path_to_num[node.path] = seq
+ uclass.alias_num_to_node[seq] = node
+ return seq
+ return None
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test.dts b/roms/u-boot/tools/dtoc/test/dtoc_test.dts
new file mode 100644
index 000000000..b2259483a
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test.dts
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+ /dts-v1/;
+
+/ {
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_add_prop.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_add_prop.dts
new file mode 100644
index 000000000..fa296e555
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_add_prop.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2018 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ intval = <1>;
+ };
+
+ spl-test2 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ intarray = <5>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_addr32.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_addr32.dts
new file mode 100644
index 000000000..239045497
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_addr32.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+ /dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ test1 {
+ u-boot,dm-pre-reloc;
+ compatible = "test1";
+ reg = <0x1234 0x5678>;
+ };
+
+ test2 {
+ u-boot,dm-pre-reloc;
+ compatible = "test2";
+ reg = <0x12345678 0x98765432 2 3>;
+ };
+
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_addr32_64.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_addr32_64.dts
new file mode 100644
index 000000000..7599d5b0a
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_addr32_64.dts
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <2>;
+
+ test1 {
+ u-boot,dm-pre-reloc;
+ compatible = "test1";
+ reg = <0x1234 0x5678 0x0>;
+ };
+
+ test2 {
+ u-boot,dm-pre-reloc;
+ compatible = "test2";
+ reg = <0x12345678 0x98765432 0x10987654>;
+ };
+
+ test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "test3";
+ reg = <0x12345678 0x98765432 0x10987654 2 0 3>;
+ };
+
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_addr64.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_addr64.dts
new file mode 100644
index 000000000..263d25138
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_addr64.dts
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+ /dts-v1/;
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ test1 {
+ u-boot,dm-pre-reloc;
+ compatible = "test1";
+ reg = /bits/ 64 <0x1234 0x5678>;
+ };
+
+ test2 {
+ u-boot,dm-pre-reloc;
+ compatible = "test2";
+ reg = /bits/ 64 <0x1234567890123456 0x9876543210987654>;
+ };
+
+ test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "test3";
+ reg = /bits/ 64 <0x1234567890123456 0x9876543210987654 2 3>;
+ };
+
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_addr64_32.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_addr64_32.dts
new file mode 100644
index 000000000..85e4f5fda
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_addr64_32.dts
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ test1 {
+ u-boot,dm-pre-reloc;
+ compatible = "test1";
+ reg = <0x1234 0x0 0x5678>;
+ };
+
+ test2 {
+ u-boot,dm-pre-reloc;
+ compatible = "test2";
+ reg = <0x12345678 0x90123456 0x98765432>;
+ };
+
+ test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "test3";
+ reg = <0x12345678 0x90123456 0x98765432 0 2 3>;
+ };
+
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad.dts
new file mode 100644
index 000000000..d4f502ad0
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ testbus2 = &bus2;
+ testfdt1 = &testfdt_1;
+ i2c4- = &i2c;
+ };
+
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ };
+
+ i2c: i2c {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,i2c";
+ intval = <3>;
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ bus2: some-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "denx,u-boot-test-bus";
+ reg = <3 1>;
+ ping-expect = <4>;
+ ping-add = <4>;
+ testfdt_1: test {
+ compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+ reg = <5>;
+ ping-expect = <5>;
+ ping-add = <5>;
+ };
+
+ test0 {
+ compatible = "google,another-fdt-test";
+ };
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad_path.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad_path.dts
new file mode 100644
index 000000000..0beca4f0d
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad_path.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ testbus2 = &bus2;
+ testfdt1 = &testfdt_1;
+ i2c4 = "/does/not/exist";
+ };
+
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ };
+
+ i2c: i2c {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,i2c";
+ intval = <3>;
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ bus2: some-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "denx,u-boot-test-bus";
+ reg = <3 1>;
+ ping-expect = <4>;
+ ping-add = <4>;
+ testfdt_1: test {
+ compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+ reg = <5>;
+ ping-expect = <5>;
+ ping-add = <5>;
+ };
+
+ test0 {
+ compatible = "google,another-fdt-test";
+ };
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad_uc.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad_uc.dts
new file mode 100644
index 000000000..ae64f5b3b
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_alias_bad_uc.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ testbus2 = &bus2;
+ testfdt1 = &testfdt_1;
+ other1 = &testfdt_1;
+ };
+
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ };
+
+ i2c: i2c {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,i2c";
+ intval = <3>;
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ bus2: some-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "denx,u-boot-test-bus";
+ reg = <3 1>;
+ ping-expect = <4>;
+ ping-add = <4>;
+ testfdt_1: test {
+ compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+ reg = <5>;
+ ping-expect = <5>;
+ ping-add = <5>;
+ };
+
+ test0 {
+ compatible = "google,another-fdt-test";
+ };
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_aliases.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_aliases.dts
new file mode 100644
index 000000000..ae3371686
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_aliases.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+ /dts-v1/;
+
+/ {
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "compat1", "compat2.1-fred", "compat3";
+ intval = <1>;
+ };
+
+ spl-test2 {
+ u-boot,dm-pre-reloc;
+ compatible = "compat1", "simple_bus";
+ intval = <1>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_bad_reg.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_bad_reg.dts
new file mode 100644
index 000000000..1312acb61
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_bad_reg.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2018 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spl-test {
+ compatible = "test";
+ reg = "fre";
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_bad_reg2.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_bad_reg2.dts
new file mode 100644
index 000000000..3e9efa43a
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_bad_reg2.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2018 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spl-test {
+ compatible = "test";
+ reg = <1 2 3>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_driver_alias.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_driver_alias.dts
new file mode 100644
index 000000000..da7973b2e
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_driver_alias.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2020 Collabora Ltd.
+ */
+
+/dts-v1/;
+
+/ {
+ gpio_a: gpios@0 {
+ u-boot,dm-pre-reloc;
+ gpio-controller;
+ compatible = "sandbox_gpio_alias";
+ #gpio-cells = <1>;
+ gpio-bank-name = "a";
+ sandbox,gpio-count = <20>;
+ };
+
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_empty.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_empty.dts
new file mode 100644
index 000000000..b2259483a
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_empty.dts
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+ /dts-v1/;
+
+/ {
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_inst.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_inst.dts
new file mode 100644
index 000000000..b8177fcef
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_inst.dts
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ testbus2 = &bus2;
+ testfdt1 = &testfdt_1;
+ i2c4 = &i2c;
+ };
+
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ };
+
+ i2c: i2c {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,i2c";
+ intval = <3>;
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ bus2: some-bus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "denx,u-boot-test-bus";
+ reg = <3 1>;
+ ping-expect = <4>;
+ ping-add = <4>;
+ testfdt_1: test {
+ compatible = "denx,u-boot-fdt-test", "google,another-fdt-test";
+ reg = <5>;
+ ping-expect = <5>;
+ ping-add = <5>;
+ };
+
+ test0 {
+ compatible = "google,another-fdt-test";
+ };
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_invalid_driver.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_invalid_driver.dts
new file mode 100644
index 000000000..914ac3e89
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_invalid_driver.dts
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "invalid";
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_noprops.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_noprops.dts
new file mode 100644
index 000000000..e6fdd11b8
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_noprops.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ i2c@0 {
+ pmic@9 {
+ compatible = "sandbox,pmic";
+ u-boot,dm-pre-reloc;
+ reg = <9>;
+ low-power;
+ };
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_phandle.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle.dts
new file mode 100644
index 000000000..a71acffc6
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle.dts
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+ /dts-v1/;
+
+/ {
+ phandle: phandle-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ intval = <0>;
+ #clock-cells = <0>;
+ };
+
+ phandle_1: phandle2-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ intval = <1>;
+ #clock-cells = <1>;
+ };
+ phandle_2: phandle3-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ intval = <2>;
+ #clock-cells = <2>;
+ };
+
+ phandle-source {
+ u-boot,dm-pre-reloc;
+ compatible = "source";
+ clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
+ };
+
+ phandle-source2 {
+ u-boot,dm-pre-reloc;
+ compatible = "source";
+ clocks = <&phandle>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_bad.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_bad.dts
new file mode 100644
index 000000000..a3ddc5958
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_bad.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2018 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ phandle-source {
+ u-boot,dm-pre-reloc;
+ compatible = "source";
+ clocks = <20>; /* Invalid phandle */
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_bad2.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_bad2.dts
new file mode 100644
index 000000000..fe25f565f
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_bad2.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2018 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ phandle: phandle-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ intval = <0>;
+ };
+
+ phandle-source2 {
+ u-boot,dm-pre-reloc;
+ compatible = "source";
+ clocks = <&phandle>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts
new file mode 100644
index 000000000..241743e73
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2020 Collabora Ltd.
+ */
+
+/dts-v1/;
+
+/ {
+ phandle: phandle-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ intval = <0>;
+ #gpio-cells = <0>;
+ };
+
+ phandle_1: phandle2-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ intval = <1>;
+ #gpio-cells = <1>;
+ };
+ phandle_2: phandle3-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ intval = <2>;
+ #gpio-cells = <2>;
+ };
+
+ phandle-source {
+ u-boot,dm-pre-reloc;
+ compatible = "source";
+ cd-gpios = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
+ };
+
+ phandle-source2 {
+ u-boot,dm-pre-reloc;
+ compatible = "source";
+ cd-gpios = <&phandle>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_reorder.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_reorder.dts
new file mode 100644
index 000000000..aa71d56f2
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_reorder.dts
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2018 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+
+ phandle-source2 {
+ u-boot,dm-pre-reloc;
+ compatible = "source";
+ clocks = <&phandle>;
+ };
+
+ phandle: phandle-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ #clock-cells = <0>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_single.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_single.dts
new file mode 100644
index 000000000..aacd0b15f
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_phandle_single.dts
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2018 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ phandle: phandle-target {
+ u-boot,dm-pre-reloc;
+ compatible = "target";
+ intval = <0>;
+ #clock-cells = <0>;
+ };
+
+ phandle-source2 {
+ u-boot,dm-pre-reloc;
+ compatible = "source";
+ clocks = <&phandle>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_scan_drivers.cxx b/roms/u-boot/tools/dtoc/test/dtoc_test_scan_drivers.cxx
new file mode 100644
index 000000000..f370b8951
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_scan_drivers.cxx
@@ -0,0 +1,5 @@
+/* Aliases must be in driver files */
+U_BOOT_DRIVER(sandbox_gpio) {
+};
+
+DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2)
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_simple.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_simple.dts
new file mode 100644
index 000000000..b5c1274bb
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_simple.dts
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+ /dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spl-test {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ boolval;
+ intval = <1>;
+ intarray = <2 3 4>;
+ byteval = [05];
+ bytearray = [06];
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10 11];
+ stringval = "message";
+ stringarray = "multi-word", "message";
+ notstring = [20 21 22 10 00];
+ };
+
+ spl-test2 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ intval = <3>;
+ intarray = <5>;
+ byteval = [08];
+ bytearray = [01 23 34];
+ longbytearray = [09 0a 0b 0c];
+ stringval = "message2";
+ stringarray = "another", "multi-word", "message";
+ acpi-name = "\\_SB.GPO0";
+ };
+
+ spl-test3 {
+ u-boot,dm-pre-reloc;
+ compatible = "sandbox,spl-test";
+ stringarray = "one";
+ longbytearray = [09 0a 0b 0c 0d 0e 0f 10];
+ };
+
+ i2c@0 {
+ compatible = "sandbox,i2c";
+ u-boot,dm-pre-reloc;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pmic@9 {
+ compatible = "sandbox,pmic";
+ u-boot,dm-pre-reloc;
+ reg = <9>;
+ low-power;
+ };
+ };
+
+ orig-node {
+ orig = <1 23 4>;
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test/dtoc_test_single_reg.dts b/roms/u-boot/tools/dtoc/test/dtoc_test_single_reg.dts
new file mode 100644
index 000000000..804b67855
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test/dtoc_test_single_reg.dts
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test device tree file for dtoc
+ *
+ * Copyright 2017 Google, Inc
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ i2c@0 {
+ compatible = "sandbox,i2c";
+ u-boot,dm-pre-reloc;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pmic@9 {
+ compatible = "sandbox,pmic";
+ u-boot,dm-pre-reloc;
+ reg = <9>;
+ low-power;
+
+ gpio {
+ compatible = "sandbox,gpio";
+ };
+ };
+ };
+};
diff --git a/roms/u-boot/tools/dtoc/test_dtoc.py b/roms/u-boot/tools/dtoc/test_dtoc.py
new file mode 100755
index 000000000..0b2805fee
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test_dtoc.py
@@ -0,0 +1,1832 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+
+"""Tests for the dtb_platdata module
+
+This includes unit tests for some functions and functional tests for the dtoc
+tool.
+"""
+
+import collections
+import copy
+import glob
+import os
+import struct
+import unittest
+
+from dtb_platdata import Ftype
+from dtb_platdata import get_value
+from dtb_platdata import tab_to
+from dtoc import dtb_platdata
+from dtoc import fdt
+from dtoc import fdt_util
+from dtoc import src_scan
+from dtoc.src_scan import conv_name_to_c
+from dtoc.src_scan import get_compat_name
+from patman import test_util
+from patman import tools
+
+OUR_PATH = os.path.dirname(os.path.realpath(__file__))
+
+
+HEADER = '''/*
+ * DO NOT MODIFY
+ *
+ * Defines the structs used to hold devicetree data.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+#include <stdbool.h>
+#include <linux/libfdt.h>'''
+
+DECL_HEADER = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares externs for all device/uclass instances.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+'''
+
+C_HEADER_PRE = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the U_BOOT_DRIVER() records and platform data.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+'''
+
+C_HEADER = C_HEADER_PRE + '''
+/* Allow use of U_BOOT_DRVINFO() in this file */
+#define DT_PLAT_C
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+'''
+
+UCLASS_HEADER_COMMON = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the uclass instances (struct uclass).
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+'''
+
+# Scanner saved from a previous run of the tests (to speed things up)
+saved_scan = None
+
+# This is a test so is allowed to access private things in the module it is
+# testing
+# pylint: disable=W0212
+
+def get_dtb_file(dts_fname, capture_stderr=False):
+ """Compile a .dts file to a .dtb
+
+ Args:
+ dts_fname (str): Filename of .dts file in the current directory
+ capture_stderr (bool): True to capture and discard stderr output
+
+ Returns:
+ str: Filename of compiled file in output directory
+ """
+ return fdt_util.EnsureCompiled(os.path.join(OUR_PATH, 'test', dts_fname),
+ capture_stderr=capture_stderr)
+
+
+def setup():
+ global saved_scan
+
+ # Disable warnings so that calls to get_normalized_compat_name() will not
+ # output things.
+ saved_scan = src_scan.Scanner(None, False)
+ saved_scan.scan_drivers()
+
+def copy_scan():
+ """Get a copy of saved_scan so that each test can start clean"""
+ return copy.deepcopy(saved_scan)
+
+
+class TestDtoc(unittest.TestCase):
+ """Tests for dtoc"""
+ @classmethod
+ def setUpClass(cls):
+ tools.PrepareOutputDir(None)
+ cls.maxDiff = None
+
+ @classmethod
+ def tearDownClass(cls):
+ tools.FinaliseOutputDir()
+
+ @staticmethod
+ def _write_python_string(fname, data):
+ """Write a string with tabs expanded as done in this Python file
+
+ Args:
+ fname (str): Filename to write to
+ data (str): Raw string to convert
+ """
+ data = data.replace('\t', '\\t')
+ with open(fname, 'w') as fout:
+ fout.write(data)
+
+ def _check_strings(self, expected, actual):
+ """Check that a string matches its expected value
+
+ If the strings do not match, they are written to the /tmp directory in
+ the same Python format as is used here in the test. This allows for
+ easy comparison and update of the tests.
+
+ Args:
+ expected (str): Expected string
+ actual (str): Actual string
+ """
+ if expected != actual:
+ self._write_python_string('/tmp/binman.expected', expected)
+ self._write_python_string('/tmp/binman.actual', actual)
+ print('Failures written to /tmp/binman.{expected,actual}')
+ self.assertEqual(expected, actual)
+
+ @staticmethod
+ def run_test(args, dtb_file, output, instantiate=False):
+ """Run a test using dtoc
+
+ Args:
+ args (list of str): List of arguments for dtoc
+ dtb_file (str): Filename of .dtb file
+ output (str): Filename of output file
+
+ Returns:
+ DtbPlatdata object
+ """
+ # Make a copy of the 'scan' object, since it includes uclasses and
+ # drivers, which get updated during execution.
+ return dtb_platdata.run_steps(
+ args, dtb_file, False, output, [], None, instantiate,
+ warning_disabled=True, scan=copy_scan())
+
+ def test_name(self):
+ """Test conversion of device tree names to C identifiers"""
+ self.assertEqual('serial_at_0x12', conv_name_to_c('serial@0x12'))
+ self.assertEqual('vendor_clock_frequency',
+ conv_name_to_c('vendor,clock-frequency'))
+ self.assertEqual('rockchip_rk3399_sdhci_5_1',
+ conv_name_to_c('rockchip,rk3399-sdhci-5.1'))
+
+ def test_tab_to(self):
+ """Test operation of tab_to() function"""
+ self.assertEqual('fred ', tab_to(0, 'fred'))
+ self.assertEqual('fred\t', tab_to(1, 'fred'))
+ self.assertEqual('fred was here ', tab_to(1, 'fred was here'))
+ self.assertEqual('fred was here\t\t', tab_to(3, 'fred was here'))
+ self.assertEqual('exactly8 ', tab_to(1, 'exactly8'))
+ self.assertEqual('exactly8\t', tab_to(2, 'exactly8'))
+
+ def test_get_value(self):
+ """Test operation of get_value() function"""
+ self.assertEqual('0x45',
+ get_value(fdt.Type.INT, struct.pack('>I', 0x45)))
+ self.assertEqual('0x45',
+ get_value(fdt.Type.BYTE, struct.pack('<I', 0x45)))
+ self.assertEqual('0x0',
+ get_value(fdt.Type.BYTE, struct.pack('>I', 0x45)))
+ self.assertEqual('"test"', get_value(fdt.Type.STRING, 'test'))
+ self.assertEqual('true', get_value(fdt.Type.BOOL, None))
+
+ def test_get_compat_name(self):
+ """Test operation of get_compat_name() function"""
+ Prop = collections.namedtuple('Prop', ['value'])
+ Node = collections.namedtuple('Node', ['props'])
+
+ prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1'])
+ node = Node({'compatible': prop})
+ self.assertEqual((['rockchip_rk3399_sdhci_5_1', 'arasan_sdhci_5_1']),
+ get_compat_name(node))
+
+ prop = Prop(['rockchip,rk3399-sdhci-5.1'])
+ node = Node({'compatible': prop})
+ self.assertEqual((['rockchip_rk3399_sdhci_5_1']),
+ get_compat_name(node))
+
+ prop = Prop(['rockchip,rk3399-sdhci-5.1', 'arasan,sdhci-5.1', 'third'])
+ node = Node({'compatible': prop})
+ self.assertEqual((['rockchip_rk3399_sdhci_5_1',
+ 'arasan_sdhci_5_1', 'third']),
+ get_compat_name(node))
+
+ def test_empty_file(self):
+ """Test output from a device tree file with no nodes"""
+ dtb_file = get_dtb_file('dtoc_test_empty.dts')
+ output = tools.GetOutputFilename('output')
+
+ # Run this one without saved_scan to complete test coverage
+ dtb_platdata.run_steps(['struct'], dtb_file, False, output, [], None,
+ False)
+ with open(output) as infile:
+ lines = infile.read().splitlines()
+ self.assertEqual(HEADER.splitlines(), lines)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ lines = infile.read().splitlines()
+ self.assertEqual(C_HEADER.splitlines() + [''], lines)
+
+ decl_text = DECL_HEADER + '''
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+/* driver declarations - these allow DM_DRIVER_GET() to be used */
+extern U_BOOT_DRIVER(sandbox_i2c);
+extern U_BOOT_DRIVER(sandbox_pmic);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+
+/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
+extern UCLASS_DRIVER(i2c);
+extern UCLASS_DRIVER(misc);
+extern UCLASS_DRIVER(pmic);
+'''
+ decl_text_inst = DECL_HEADER + '''
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+
+/* driver declarations - these allow DM_DRIVER_GET() to be used */
+extern U_BOOT_DRIVER(sandbox_i2c);
+extern U_BOOT_DRIVER(root_driver);
+extern U_BOOT_DRIVER(denx_u_boot_test_bus);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+extern U_BOOT_DRIVER(sandbox_spl_test);
+extern U_BOOT_DRIVER(denx_u_boot_fdt_test);
+extern U_BOOT_DRIVER(denx_u_boot_fdt_test);
+
+/* device declarations - these allow DM_DEVICE_REF() to be used */
+extern DM_DEVICE_INST(i2c);
+extern DM_DEVICE_INST(root);
+extern DM_DEVICE_INST(some_bus);
+extern DM_DEVICE_INST(spl_test);
+extern DM_DEVICE_INST(spl_test3);
+extern DM_DEVICE_INST(test);
+extern DM_DEVICE_INST(test0);
+
+/* uclass driver declarations - needed for DM_UCLASS_DRIVER_REF() */
+extern UCLASS_DRIVER(i2c);
+extern UCLASS_DRIVER(misc);
+extern UCLASS_DRIVER(root);
+extern UCLASS_DRIVER(testbus);
+extern UCLASS_DRIVER(testfdt);
+
+/* uclass declarations - needed for DM_UCLASS_REF() */
+extern DM_UCLASS_INST(i2c);
+extern DM_UCLASS_INST(misc);
+extern DM_UCLASS_INST(root);
+extern DM_UCLASS_INST(testbus);
+extern DM_UCLASS_INST(testfdt);
+'''
+ struct_text = HEADER + '''
+struct dtd_sandbox_i2c {
+};
+struct dtd_sandbox_pmic {
+\tbool\t\tlow_power;
+\tfdt32_t\t\treg[1];
+};
+struct dtd_sandbox_spl_test {
+\tconst char * acpi_name;
+\tbool\t\tboolval;
+\tunsigned char\tbytearray[3];
+\tunsigned char\tbyteval;
+\tfdt32_t\t\tintarray[4];
+\tfdt32_t\t\tintval;
+\tunsigned char\tlongbytearray[9];
+\tunsigned char\tnotstring[5];
+\tconst char *\tstringarray[3];
+\tconst char *\tstringval;
+};
+'''
+ platdata_text = C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: i2c_at_0 sandbox_i2c
+ * 1: pmic_at_9 sandbox_pmic
+ * 2: spl_test sandbox_spl_test
+ * 3: spl_test2 sandbox_spl_test
+ * 4: spl_test3 sandbox_spl_test
+ * --- -------------------- --------------------
+ */
+
+/*
+ * Node /i2c@0 index 0
+ * driver sandbox_i2c parent None
+ */
+static struct dtd_sandbox_i2c dtv_i2c_at_0 = {
+};
+U_BOOT_DRVINFO(i2c_at_0) = {
+\t.name\t\t= "sandbox_i2c",
+\t.plat\t\t= &dtv_i2c_at_0,
+\t.plat_size\t= sizeof(dtv_i2c_at_0),
+\t.parent_idx\t= -1,
+};
+
+/*
+ * Node /i2c@0/pmic@9 index 1
+ * driver sandbox_pmic parent sandbox_i2c
+ */
+static struct dtd_sandbox_pmic dtv_pmic_at_9 = {
+\t.low_power\t\t= true,
+\t.reg\t\t\t= {0x9},
+};
+U_BOOT_DRVINFO(pmic_at_9) = {
+\t.name\t\t= "sandbox_pmic",
+\t.plat\t\t= &dtv_pmic_at_9,
+\t.plat_size\t= sizeof(dtv_pmic_at_9),
+\t.parent_idx\t= 0,
+};
+
+/*
+ * Node /spl-test index 2
+ * driver sandbox_spl_test parent None
+ */
+static struct dtd_sandbox_spl_test dtv_spl_test = {
+\t.boolval\t\t= true,
+\t.bytearray\t\t= {0x6, 0x0, 0x0},
+\t.byteval\t\t= 0x5,
+\t.intarray\t\t= {0x2, 0x3, 0x4, 0x0},
+\t.intval\t\t\t= 0x1,
+\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
+\t\t0x11},
+\t.notstring\t\t= {0x20, 0x21, 0x22, 0x10, 0x0},
+\t.stringarray\t\t= {"multi-word", "message", ""},
+\t.stringval\t\t= "message",
+};
+U_BOOT_DRVINFO(spl_test) = {
+\t.name\t\t= "sandbox_spl_test",
+\t.plat\t\t= &dtv_spl_test,
+\t.plat_size\t= sizeof(dtv_spl_test),
+\t.parent_idx\t= -1,
+};
+
+/*
+ * Node /spl-test2 index 3
+ * driver sandbox_spl_test parent None
+ */
+static struct dtd_sandbox_spl_test dtv_spl_test2 = {
+\t.acpi_name\t\t= "\\\\_SB.GPO0",
+\t.bytearray\t\t= {0x1, 0x23, 0x34},
+\t.byteval\t\t= 0x8,
+\t.intarray\t\t= {0x5, 0x0, 0x0, 0x0},
+\t.intval\t\t\t= 0x3,
+\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0x0, 0x0, 0x0, 0x0,
+\t\t0x0},
+\t.stringarray\t\t= {"another", "multi-word", "message"},
+\t.stringval\t\t= "message2",
+};
+U_BOOT_DRVINFO(spl_test2) = {
+\t.name\t\t= "sandbox_spl_test",
+\t.plat\t\t= &dtv_spl_test2,
+\t.plat_size\t= sizeof(dtv_spl_test2),
+\t.parent_idx\t= -1,
+};
+
+/*
+ * Node /spl-test3 index 4
+ * driver sandbox_spl_test parent None
+ */
+static struct dtd_sandbox_spl_test dtv_spl_test3 = {
+\t.longbytearray\t\t= {0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
+\t\t0x0},
+\t.stringarray\t\t= {"one", "", ""},
+};
+U_BOOT_DRVINFO(spl_test3) = {
+\t.name\t\t= "sandbox_spl_test",
+\t.plat\t\t= &dtv_spl_test3,
+\t.plat_size\t= sizeof(dtv_spl_test3),
+\t.parent_idx\t= -1,
+};
+
+'''
+ uclass_text_inst = '''
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+/*
+ * uclass declarations, ordered by 'struct uclass' linker_list idx:
+ * 0: i2c
+ * 1: misc
+ * 2: root
+ * 3: testbus
+ * 4: testfdt
+ *
+ * Sequence numbers allocated in each uclass:
+ * i2c: UCLASS_I2C
+ * 4: /i2c
+ * misc: UCLASS_MISC
+ * 0: /spl-test
+ * 1: /spl-test3
+ * root: UCLASS_ROOT
+ * 0: /
+ * testbus: UCLASS_TEST_BUS
+ * 2: /some-bus
+ * testfdt: UCLASS_TEST_FDT
+ * 1: /some-bus/test
+ * 2: /some-bus/test0
+ */
+
+struct list_head uclass_head = {
+ .prev = &DM_UCLASS_REF(testfdt)->sibling_node,
+ .next = &DM_UCLASS_REF(i2c)->sibling_node,
+};
+
+DM_UCLASS_INST(i2c) = {
+ .uc_drv = DM_UCLASS_DRIVER_REF(i2c),
+ .sibling_node = {
+ .prev = &uclass_head,
+ .next = &DM_UCLASS_REF(misc)->sibling_node,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(i2c)->uclass_node,
+ .next = &DM_DEVICE_REF(i2c)->uclass_node,
+ },
+};
+
+DM_UCLASS_INST(misc) = {
+ .uc_drv = DM_UCLASS_DRIVER_REF(misc),
+ .sibling_node = {
+ .prev = &DM_UCLASS_REF(i2c)->sibling_node,
+ .next = &DM_UCLASS_REF(root)->sibling_node,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(spl_test3)->uclass_node,
+ .next = &DM_DEVICE_REF(spl_test)->uclass_node,
+ },
+};
+
+DM_UCLASS_INST(root) = {
+ .uc_drv = DM_UCLASS_DRIVER_REF(root),
+ .sibling_node = {
+ .prev = &DM_UCLASS_REF(misc)->sibling_node,
+ .next = &DM_UCLASS_REF(testbus)->sibling_node,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(root)->uclass_node,
+ .next = &DM_DEVICE_REF(root)->uclass_node,
+ },
+};
+
+DM_UCLASS_INST(testbus) = {
+ .uc_drv = DM_UCLASS_DRIVER_REF(testbus),
+ .sibling_node = {
+ .prev = &DM_UCLASS_REF(root)->sibling_node,
+ .next = &DM_UCLASS_REF(testfdt)->sibling_node,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(some_bus)->uclass_node,
+ .next = &DM_DEVICE_REF(some_bus)->uclass_node,
+ },
+};
+
+#include <dm/test.h>
+u8 _testfdt_priv_[sizeof(struct dm_test_uc_priv)]
+ __attribute__ ((section (".priv_data")));
+DM_UCLASS_INST(testfdt) = {
+ .priv_ = _testfdt_priv_,
+ .uc_drv = DM_UCLASS_DRIVER_REF(testfdt),
+ .sibling_node = {
+ .prev = &DM_UCLASS_REF(testbus)->sibling_node,
+ .next = &uclass_head,
+ },
+ .dev_head = {
+ .prev = &DM_DEVICE_REF(test0)->uclass_node,
+ .next = &DM_DEVICE_REF(test)->uclass_node,
+ },
+};
+
+'''
+ device_text_inst = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the DM_DEVICE_INST() records.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+/*
+ * udevice declarations, ordered by 'struct udevice' linker_list position:
+ *
+ * idx udevice driver
+ * --- -------------------- --------------------
+ * 0: i2c sandbox_i2c
+ * 1: root root_driver
+ * 2: some_bus denx_u_boot_test_bus
+ * 3: spl_test sandbox_spl_test
+ * 4: spl_test3 sandbox_spl_test
+ * 5: test denx_u_boot_fdt_test
+ * 6: test0 denx_u_boot_fdt_test
+ * --- -------------------- --------------------
+ */
+
+/*
+ * Node /i2c index 0
+ * driver sandbox_i2c parent root_driver
+*/
+static struct dtd_sandbox_i2c dtv_i2c = {
+\t.intval\t\t\t= 0x3,
+};
+
+#include <asm/i2c.h>
+u8 _sandbox_i2c_priv_i2c[sizeof(struct sandbox_i2c_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <i2c.h>
+u8 _sandbox_i2c_uc_priv_i2c[sizeof(struct dm_i2c_bus)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(i2c) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_i2c),
+\t.name\t\t= "sandbox_i2c",
+\t.plat_\t\t= &dtv_i2c,
+\t.priv_\t\t= _sandbox_i2c_priv_i2c,
+\t.uclass\t\t= DM_UCLASS_REF(i2c),
+\t.uclass_priv_ = _sandbox_i2c_uc_priv_i2c,
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(i2c)->dev_head,
+\t\t.next = &DM_UCLASS_REF(i2c)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(i2c)->child_head,
+\t\t.next = &DM_DEVICE_REF(i2c)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(root)->child_head,
+\t\t.next = &DM_DEVICE_REF(some_bus)->sibling_node,
+\t},
+\t.seq_ = 4,
+};
+
+/*
+ * Node / index 1
+ * driver root_driver parent None
+*/
+static struct dtd_root_driver dtv_root = {
+};
+
+DM_DEVICE_INST(root) = {
+\t.driver\t\t= DM_DRIVER_REF(root_driver),
+\t.name\t\t= "root_driver",
+\t.plat_\t\t= &dtv_root,
+\t.uclass\t\t= DM_UCLASS_REF(root),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(root)->dev_head,
+\t\t.next = &DM_UCLASS_REF(root)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test3)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(i2c)->sibling_node,
+\t},
+\t.seq_ = 0,
+};
+
+/*
+ * Node /some-bus index 2
+ * driver denx_u_boot_test_bus parent root_driver
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_test_bus_plat_some_bus = {
+\t.dtplat = {
+\t\t.ping_add\t\t= 0x4,
+\t\t.ping_expect\t\t= 0x4,
+\t\t.reg\t\t\t= {0x3, 0x1},
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_test_bus_priv_some_bus[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_test_bus_ucplat_some_bus[sizeof(struct dm_test_uclass_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <test.h>
+
+DM_DEVICE_INST(some_bus) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_test_bus),
+\t.name\t\t= "denx_u_boot_test_bus",
+\t.plat_\t\t= &_denx_u_boot_test_bus_plat_some_bus,
+\t.uclass_plat_\t= _denx_u_boot_test_bus_ucplat_some_bus,
+\t.driver_data\t= DM_TEST_TYPE_FIRST,
+\t.priv_\t\t= _denx_u_boot_test_bus_priv_some_bus,
+\t.uclass\t\t= DM_UCLASS_REF(testbus),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(testbus)->dev_head,
+\t\t.next = &DM_UCLASS_REF(testbus)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test0)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(test)->sibling_node,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(i2c)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(spl_test)->sibling_node,
+\t},
+\t.seq_ = 2,
+};
+
+/*
+ * Node /spl-test index 3
+ * driver sandbox_spl_test parent root_driver
+*/
+static struct dtd_sandbox_spl_test dtv_spl_test = {
+\t.boolval\t\t= true,
+\t.intval\t\t\t= 0x1,
+};
+
+DM_DEVICE_INST(spl_test) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
+\t.name\t\t= "sandbox_spl_test",
+\t.plat_\t\t= &dtv_spl_test,
+\t.uclass\t\t= DM_UCLASS_REF(misc),
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(misc)->dev_head,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->uclass_node,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->child_head,
+\t\t.next = &DM_DEVICE_REF(spl_test)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(some_bus)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->sibling_node,
+\t},
+\t.seq_ = 0,
+};
+
+/*
+ * Node /spl-test3 index 4
+ * driver sandbox_spl_test parent root_driver
+*/
+static struct dtd_sandbox_spl_test dtv_spl_test3 = {
+\t.longbytearray\t\t= {0x90a0b0c, 0xd0e0f10},
+\t.stringarray\t\t= "one",
+};
+
+DM_DEVICE_INST(spl_test3) = {
+\t.driver\t\t= DM_DRIVER_REF(sandbox_spl_test),
+\t.name\t\t= "sandbox_spl_test",
+\t.plat_\t\t= &dtv_spl_test3,
+\t.uclass\t\t= DM_UCLASS_REF(misc),
+\t.uclass_node\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->uclass_node,
+\t\t.next = &DM_UCLASS_REF(misc)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test3)->child_head,
+\t\t.next = &DM_DEVICE_REF(spl_test3)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(spl_test)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(root)->child_head,
+\t},
+\t.seq_ = 1,
+};
+
+/*
+ * Node /some-bus/test index 5
+ * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_fdt_test_plat_test = {
+\t.dtplat = {
+\t\t.ping_add\t\t= 0x5,
+\t\t.ping_expect\t\t= 0x5,
+\t\t.reg\t\t\t= {0x5},
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_priv_test[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_plat_test[sizeof(struct dm_test_parent_plat)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_priv_test[sizeof(struct dm_test_parent_data)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(test) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
+\t.name\t\t= "denx_u_boot_fdt_test",
+\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test,
+\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test,
+\t.driver_data\t= DM_TEST_TYPE_FIRST,
+\t.parent\t\t= DM_DEVICE_REF(some_bus),
+\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test,
+\t.uclass\t\t= DM_UCLASS_REF(testfdt),
+\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test,
+\t.uclass_node\t= {
+\t\t.prev = &DM_UCLASS_REF(testfdt)->dev_head,
+\t\t.next = &DM_DEVICE_REF(test0)->uclass_node,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->child_head,
+\t\t.next = &DM_DEVICE_REF(test)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(some_bus)->child_head,
+\t\t.next = &DM_DEVICE_REF(test0)->sibling_node,
+\t},
+\t.seq_ = 1,
+};
+
+/*
+ * Node /some-bus/test0 index 6
+ * driver denx_u_boot_fdt_test parent denx_u_boot_test_bus
+*/
+
+#include <dm/test.h>
+struct dm_test_pdata __attribute__ ((section (".priv_data")))
+\t_denx_u_boot_fdt_test_plat_test0 = {
+\t.dtplat = {
+\t},
+};
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_priv_test0[sizeof(struct dm_test_priv)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_plat_test0[sizeof(struct dm_test_parent_plat)]
+\t__attribute__ ((section (".priv_data")));
+#include <dm/test.h>
+u8 _denx_u_boot_fdt_test_parent_priv_test0[sizeof(struct dm_test_parent_data)]
+\t__attribute__ ((section (".priv_data")));
+
+DM_DEVICE_INST(test0) = {
+\t.driver\t\t= DM_DRIVER_REF(denx_u_boot_fdt_test),
+\t.name\t\t= "denx_u_boot_fdt_test",
+\t.plat_\t\t= &_denx_u_boot_fdt_test_plat_test0,
+\t.parent_plat_\t= _denx_u_boot_fdt_test_parent_plat_test0,
+\t.driver_data\t= DM_TEST_TYPE_SECOND,
+\t.parent\t\t= DM_DEVICE_REF(some_bus),
+\t.priv_\t\t= _denx_u_boot_fdt_test_priv_test0,
+\t.uclass\t\t= DM_UCLASS_REF(testfdt),
+\t.parent_priv_\t= _denx_u_boot_fdt_test_parent_priv_test0,
+\t.uclass_node\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->uclass_node,
+\t\t.next = &DM_UCLASS_REF(testfdt)->dev_head,
+\t},
+\t.child_head\t= {
+\t\t.prev = &DM_DEVICE_REF(test0)->child_head,
+\t\t.next = &DM_DEVICE_REF(test0)->child_head,
+\t},
+\t.sibling_node\t= {
+\t\t.prev = &DM_DEVICE_REF(test)->sibling_node,
+\t\t.next = &DM_DEVICE_REF(some_bus)->child_head,
+\t},
+\t.seq_ = 2,
+};
+
+'''
+
+ def test_simple(self):
+ """Test output from some simple nodes with various types of data"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.struct_text, data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.platdata_text, data)
+
+ self.run_test(['decl'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.decl_text, data)
+
+ # Try the 'all' command
+ self.run_test(['all'], dtb_file, output)
+ data = tools.ReadFile(output, binary=False)
+ self._check_strings(
+ self.decl_text + self.platdata_text + self.struct_text, data)
+
+ def test_driver_alias(self):
+ """Test output from a device tree file with a driver alias"""
+ dtb_file = get_dtb_file('dtoc_test_driver_alias.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_sandbox_gpio {
+\tconst char *\tgpio_bank_name;
+\tbool\t\tgpio_controller;
+\tfdt32_t\t\tsandbox_gpio_count;
+};
+''', data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: gpios_at_0 sandbox_gpio
+ * --- -------------------- --------------------
+ */
+
+/*
+ * Node /gpios@0 index 0
+ * driver sandbox_gpio parent None
+ */
+static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
+\t.gpio_bank_name\t\t= "a",
+\t.gpio_controller\t= true,
+\t.sandbox_gpio_count\t= 0x14,
+};
+U_BOOT_DRVINFO(gpios_at_0) = {
+\t.name\t\t= "sandbox_gpio",
+\t.plat\t\t= &dtv_gpios_at_0,
+\t.plat_size\t= sizeof(dtv_gpios_at_0),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_invalid_driver(self):
+ """Test output from a device tree file with an invalid driver"""
+ dtb_file = get_dtb_file('dtoc_test_invalid_driver.dts')
+ output = tools.GetOutputFilename('output')
+ with test_util.capture_sys_output() as _:
+ dtb_platdata.run_steps(
+ ['struct'], dtb_file, False, output, [], None, False,
+ scan=copy_scan())
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_invalid {
+};
+''', data)
+
+ with test_util.capture_sys_output() as _:
+ dtb_platdata.run_steps(
+ ['platdata'], dtb_file, False, output, [], None, False,
+ scan=copy_scan())
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: spl_test invalid
+ * --- -------------------- --------------------
+ */
+
+/* Node /spl-test index 0 */
+static struct dtd_invalid dtv_spl_test = {
+};
+U_BOOT_DRVINFO(spl_test) = {
+\t.name\t\t= "invalid",
+\t.plat\t\t= &dtv_spl_test,
+\t.plat_size\t= sizeof(dtv_spl_test),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_phandle(self):
+ """Test output from a node containing a phandle reference"""
+ dtb_file = get_dtb_file('dtoc_test_phandle.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_source {
+\tstruct phandle_2_arg clocks[4];
+};
+struct dtd_target {
+\tfdt32_t\t\tintval;
+};
+''', data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: phandle2_target target
+ * 1: phandle3_target target
+ * 2: phandle_source source
+ * 3: phandle_source2 source
+ * 4: phandle_target target
+ * --- -------------------- --------------------
+ */
+
+/* Node /phandle2-target index 0 */
+static struct dtd_target dtv_phandle2_target = {
+\t.intval\t\t\t= 0x1,
+};
+U_BOOT_DRVINFO(phandle2_target) = {
+\t.name\t\t= "target",
+\t.plat\t\t= &dtv_phandle2_target,
+\t.plat_size\t= sizeof(dtv_phandle2_target),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle3-target index 1 */
+static struct dtd_target dtv_phandle3_target = {
+\t.intval\t\t\t= 0x2,
+};
+U_BOOT_DRVINFO(phandle3_target) = {
+\t.name\t\t= "target",
+\t.plat\t\t= &dtv_phandle3_target,
+\t.plat_size\t= sizeof(dtv_phandle3_target),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle-source index 2 */
+static struct dtd_source dtv_phandle_source = {
+\t.clocks\t\t\t= {
+\t\t\t{4, {}},
+\t\t\t{0, {11}},
+\t\t\t{1, {12, 13}},
+\t\t\t{4, {}},},
+};
+U_BOOT_DRVINFO(phandle_source) = {
+\t.name\t\t= "source",
+\t.plat\t\t= &dtv_phandle_source,
+\t.plat_size\t= sizeof(dtv_phandle_source),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle-source2 index 3 */
+static struct dtd_source dtv_phandle_source2 = {
+\t.clocks\t\t\t= {
+\t\t\t{4, {}},},
+};
+U_BOOT_DRVINFO(phandle_source2) = {
+\t.name\t\t= "source",
+\t.plat\t\t= &dtv_phandle_source2,
+\t.plat_size\t= sizeof(dtv_phandle_source2),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle-target index 4 */
+static struct dtd_target dtv_phandle_target = {
+\t.intval\t\t\t= 0x0,
+};
+U_BOOT_DRVINFO(phandle_target) = {
+\t.name\t\t= "target",
+\t.plat\t\t= &dtv_phandle_target,
+\t.plat_size\t= sizeof(dtv_phandle_target),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_phandle_single(self):
+ """Test output from a node containing a phandle reference"""
+ dtb_file = get_dtb_file('dtoc_test_phandle_single.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_source {
+\tstruct phandle_0_arg clocks[1];
+};
+struct dtd_target {
+\tfdt32_t\t\tintval;
+};
+''', data)
+
+ def test_phandle_reorder(self):
+ """Test that phandle targets are generated before their references"""
+ dtb_file = get_dtb_file('dtoc_test_phandle_reorder.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: phandle_source2 source
+ * 1: phandle_target target
+ * --- -------------------- --------------------
+ */
+
+/* Node /phandle-source2 index 0 */
+static struct dtd_source dtv_phandle_source2 = {
+\t.clocks\t\t\t= {
+\t\t\t{1, {}},},
+};
+U_BOOT_DRVINFO(phandle_source2) = {
+\t.name\t\t= "source",
+\t.plat\t\t= &dtv_phandle_source2,
+\t.plat_size\t= sizeof(dtv_phandle_source2),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle-target index 1 */
+static struct dtd_target dtv_phandle_target = {
+};
+U_BOOT_DRVINFO(phandle_target) = {
+\t.name\t\t= "target",
+\t.plat\t\t= &dtv_phandle_target,
+\t.plat_size\t= sizeof(dtv_phandle_target),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_phandle_cd_gpio(self):
+ """Test that phandle targets are generated when unsing cd-gpios"""
+ dtb_file = get_dtb_file('dtoc_test_phandle_cd_gpios.dts')
+ output = tools.GetOutputFilename('output')
+ dtb_platdata.run_steps(
+ ['platdata'], dtb_file, False, output, [], None, False,
+ warning_disabled=True, scan=copy_scan())
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: phandle2_target target
+ * 1: phandle3_target target
+ * 2: phandle_source source
+ * 3: phandle_source2 source
+ * 4: phandle_target target
+ * --- -------------------- --------------------
+ */
+
+/* Node /phandle2-target index 0 */
+static struct dtd_target dtv_phandle2_target = {
+\t.intval\t\t\t= 0x1,
+};
+U_BOOT_DRVINFO(phandle2_target) = {
+\t.name\t\t= "target",
+\t.plat\t\t= &dtv_phandle2_target,
+\t.plat_size\t= sizeof(dtv_phandle2_target),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle3-target index 1 */
+static struct dtd_target dtv_phandle3_target = {
+\t.intval\t\t\t= 0x2,
+};
+U_BOOT_DRVINFO(phandle3_target) = {
+\t.name\t\t= "target",
+\t.plat\t\t= &dtv_phandle3_target,
+\t.plat_size\t= sizeof(dtv_phandle3_target),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle-source index 2 */
+static struct dtd_source dtv_phandle_source = {
+\t.cd_gpios\t\t= {
+\t\t\t{4, {}},
+\t\t\t{0, {11}},
+\t\t\t{1, {12, 13}},
+\t\t\t{4, {}},},
+};
+U_BOOT_DRVINFO(phandle_source) = {
+\t.name\t\t= "source",
+\t.plat\t\t= &dtv_phandle_source,
+\t.plat_size\t= sizeof(dtv_phandle_source),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle-source2 index 3 */
+static struct dtd_source dtv_phandle_source2 = {
+\t.cd_gpios\t\t= {
+\t\t\t{4, {}},},
+};
+U_BOOT_DRVINFO(phandle_source2) = {
+\t.name\t\t= "source",
+\t.plat\t\t= &dtv_phandle_source2,
+\t.plat_size\t= sizeof(dtv_phandle_source2),
+\t.parent_idx\t= -1,
+};
+
+/* Node /phandle-target index 4 */
+static struct dtd_target dtv_phandle_target = {
+\t.intval\t\t\t= 0x0,
+};
+U_BOOT_DRVINFO(phandle_target) = {
+\t.name\t\t= "target",
+\t.plat\t\t= &dtv_phandle_target,
+\t.plat_size\t= sizeof(dtv_phandle_target),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_phandle_bad(self):
+ """Test a node containing an invalid phandle fails"""
+ dtb_file = get_dtb_file('dtoc_test_phandle_bad.dts',
+ capture_stderr=True)
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ self.run_test(['struct'], dtb_file, output)
+ self.assertIn("Cannot parse 'clocks' in node 'phandle-source'",
+ str(exc.exception))
+
+ def test_phandle_bad2(self):
+ """Test a phandle target missing its #*-cells property"""
+ dtb_file = get_dtb_file('dtoc_test_phandle_bad2.dts',
+ capture_stderr=True)
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ self.run_test(['struct'], dtb_file, output)
+ self.assertIn("Node 'phandle-target' has no cells property",
+ str(exc.exception))
+
+ def test_addresses64(self):
+ """Test output from a node with a 'reg' property with na=2, ns=2"""
+ dtb_file = get_dtb_file('dtoc_test_addr64.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_test1 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test2 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test3 {
+\tfdt64_t\t\treg[4];
+};
+''', data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: test1 test1
+ * 1: test2 test2
+ * 2: test3 test3
+ * --- -------------------- --------------------
+ */
+
+/* Node /test1 index 0 */
+static struct dtd_test1 dtv_test1 = {
+\t.reg\t\t\t= {0x1234, 0x5678},
+};
+U_BOOT_DRVINFO(test1) = {
+\t.name\t\t= "test1",
+\t.plat\t\t= &dtv_test1,
+\t.plat_size\t= sizeof(dtv_test1),
+\t.parent_idx\t= -1,
+};
+
+/* Node /test2 index 1 */
+static struct dtd_test2 dtv_test2 = {
+\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654},
+};
+U_BOOT_DRVINFO(test2) = {
+\t.name\t\t= "test2",
+\t.plat\t\t= &dtv_test2,
+\t.plat_size\t= sizeof(dtv_test2),
+\t.parent_idx\t= -1,
+};
+
+/* Node /test3 index 2 */
+static struct dtd_test3 dtv_test3 = {
+\t.reg\t\t\t= {0x1234567890123456, 0x9876543210987654, 0x2, 0x3},
+};
+U_BOOT_DRVINFO(test3) = {
+\t.name\t\t= "test3",
+\t.plat\t\t= &dtv_test3,
+\t.plat_size\t= sizeof(dtv_test3),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_addresses32(self):
+ """Test output from a node with a 'reg' property with na=1, ns=1"""
+ dtb_file = get_dtb_file('dtoc_test_addr32.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_test1 {
+\tfdt32_t\t\treg[2];
+};
+struct dtd_test2 {
+\tfdt32_t\t\treg[4];
+};
+''', data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: test1 test1
+ * 1: test2 test2
+ * --- -------------------- --------------------
+ */
+
+/* Node /test1 index 0 */
+static struct dtd_test1 dtv_test1 = {
+\t.reg\t\t\t= {0x1234, 0x5678},
+};
+U_BOOT_DRVINFO(test1) = {
+\t.name\t\t= "test1",
+\t.plat\t\t= &dtv_test1,
+\t.plat_size\t= sizeof(dtv_test1),
+\t.parent_idx\t= -1,
+};
+
+/* Node /test2 index 1 */
+static struct dtd_test2 dtv_test2 = {
+\t.reg\t\t\t= {0x12345678, 0x98765432, 0x2, 0x3},
+};
+U_BOOT_DRVINFO(test2) = {
+\t.name\t\t= "test2",
+\t.plat\t\t= &dtv_test2,
+\t.plat_size\t= sizeof(dtv_test2),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_addresses64_32(self):
+ """Test output from a node with a 'reg' property with na=2, ns=1"""
+ dtb_file = get_dtb_file('dtoc_test_addr64_32.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_test1 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test2 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test3 {
+\tfdt64_t\t\treg[4];
+};
+''', data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: test1 test1
+ * 1: test2 test2
+ * 2: test3 test3
+ * --- -------------------- --------------------
+ */
+
+/* Node /test1 index 0 */
+static struct dtd_test1 dtv_test1 = {
+\t.reg\t\t\t= {0x123400000000, 0x5678},
+};
+U_BOOT_DRVINFO(test1) = {
+\t.name\t\t= "test1",
+\t.plat\t\t= &dtv_test1,
+\t.plat_size\t= sizeof(dtv_test1),
+\t.parent_idx\t= -1,
+};
+
+/* Node /test2 index 1 */
+static struct dtd_test2 dtv_test2 = {
+\t.reg\t\t\t= {0x1234567890123456, 0x98765432},
+};
+U_BOOT_DRVINFO(test2) = {
+\t.name\t\t= "test2",
+\t.plat\t\t= &dtv_test2,
+\t.plat_size\t= sizeof(dtv_test2),
+\t.parent_idx\t= -1,
+};
+
+/* Node /test3 index 2 */
+static struct dtd_test3 dtv_test3 = {
+\t.reg\t\t\t= {0x1234567890123456, 0x98765432, 0x2, 0x3},
+};
+U_BOOT_DRVINFO(test3) = {
+\t.name\t\t= "test3",
+\t.plat\t\t= &dtv_test3,
+\t.plat_size\t= sizeof(dtv_test3),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_addresses32_64(self):
+ """Test output from a node with a 'reg' property with na=1, ns=2"""
+ dtb_file = get_dtb_file('dtoc_test_addr32_64.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_test1 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test2 {
+\tfdt64_t\t\treg[2];
+};
+struct dtd_test3 {
+\tfdt64_t\t\treg[4];
+};
+''', data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: test1 test1
+ * 1: test2 test2
+ * 2: test3 test3
+ * --- -------------------- --------------------
+ */
+
+/* Node /test1 index 0 */
+static struct dtd_test1 dtv_test1 = {
+\t.reg\t\t\t= {0x1234, 0x567800000000},
+};
+U_BOOT_DRVINFO(test1) = {
+\t.name\t\t= "test1",
+\t.plat\t\t= &dtv_test1,
+\t.plat_size\t= sizeof(dtv_test1),
+\t.parent_idx\t= -1,
+};
+
+/* Node /test2 index 1 */
+static struct dtd_test2 dtv_test2 = {
+\t.reg\t\t\t= {0x12345678, 0x9876543210987654},
+};
+U_BOOT_DRVINFO(test2) = {
+\t.name\t\t= "test2",
+\t.plat\t\t= &dtv_test2,
+\t.plat_size\t= sizeof(dtv_test2),
+\t.parent_idx\t= -1,
+};
+
+/* Node /test3 index 2 */
+static struct dtd_test3 dtv_test3 = {
+\t.reg\t\t\t= {0x12345678, 0x9876543210987654, 0x2, 0x3},
+};
+U_BOOT_DRVINFO(test3) = {
+\t.name\t\t= "test3",
+\t.plat\t\t= &dtv_test3,
+\t.plat_size\t= sizeof(dtv_test3),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_bad_reg(self):
+ """Test that a reg property with an invalid type generates an error"""
+ # Capture stderr since dtc will emit warnings for this file
+ dtb_file = get_dtb_file('dtoc_test_bad_reg.dts', capture_stderr=True)
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ self.run_test(['struct'], dtb_file, output)
+ self.assertIn("Node 'spl-test' reg property is not an int",
+ str(exc.exception))
+
+ def test_bad_reg2(self):
+ """Test that a reg property with an invalid cell count is detected"""
+ # Capture stderr since dtc will emit warnings for this file
+ dtb_file = get_dtb_file('dtoc_test_bad_reg2.dts', capture_stderr=True)
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ self.run_test(['struct'], dtb_file, output)
+ self.assertIn(
+ "Node 'spl-test' (parent '/') reg property has 3 cells which is not a multiple of na + ns = 1 + 1)",
+ str(exc.exception))
+
+ def test_add_prop(self):
+ """Test that a subequent node can add a new property to a struct"""
+ dtb_file = get_dtb_file('dtoc_test_add_prop.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(HEADER + '''
+struct dtd_sandbox_spl_test {
+\tfdt32_t\t\tintarray;
+\tfdt32_t\t\tintval;
+};
+''', data)
+
+ self.run_test(['platdata'], dtb_file, output)
+ with open(output) as infile:
+ data = infile.read()
+ self._check_strings(C_HEADER + '''
+/*
+ * driver_info declarations, ordered by 'struct driver_info' linker_list idx:
+ *
+ * idx driver_info driver
+ * --- -------------------- --------------------
+ * 0: spl_test sandbox_spl_test
+ * 1: spl_test2 sandbox_spl_test
+ * --- -------------------- --------------------
+ */
+
+/*
+ * Node /spl-test index 0
+ * driver sandbox_spl_test parent None
+ */
+static struct dtd_sandbox_spl_test dtv_spl_test = {
+\t.intval\t\t\t= 0x1,
+};
+U_BOOT_DRVINFO(spl_test) = {
+\t.name\t\t= "sandbox_spl_test",
+\t.plat\t\t= &dtv_spl_test,
+\t.plat_size\t= sizeof(dtv_spl_test),
+\t.parent_idx\t= -1,
+};
+
+/*
+ * Node /spl-test2 index 1
+ * driver sandbox_spl_test parent None
+ */
+static struct dtd_sandbox_spl_test dtv_spl_test2 = {
+\t.intarray\t\t= 0x5,
+};
+U_BOOT_DRVINFO(spl_test2) = {
+\t.name\t\t= "sandbox_spl_test",
+\t.plat\t\t= &dtv_spl_test2,
+\t.plat_size\t= sizeof(dtv_spl_test2),
+\t.parent_idx\t= -1,
+};
+
+''', data)
+
+ def test_stdout(self):
+ """Test output to stdout"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ with test_util.capture_sys_output() as (stdout, _):
+ self.run_test(['struct'], dtb_file, None)
+ self._check_strings(self.struct_text, stdout.getvalue())
+
+ def test_multi_to_file(self):
+ """Test output of multiple pieces to a single file"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['all'], dtb_file, output)
+ data = tools.ReadFile(output, binary=False)
+ self._check_strings(
+ self.decl_text + self.platdata_text + self.struct_text, data)
+
+ def test_no_command(self):
+ """Test running dtoc without a command"""
+ with self.assertRaises(ValueError) as exc:
+ self.run_test([], '', '')
+ self.assertIn("Please specify a command: struct, platdata",
+ str(exc.exception))
+
+ def test_bad_command(self):
+ """Test running dtoc with an invalid command"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ self.run_test(['invalid-cmd'], dtb_file, output)
+ self.assertIn(
+ "Unknown command 'invalid-cmd': (use: decl, platdata, struct)",
+ str(exc.exception))
+
+ def test_output_conflict(self):
+ """Test a conflict between and output dirs and output file"""
+ with self.assertRaises(ValueError) as exc:
+ dtb_platdata.run_steps(
+ ['all'], None, False, 'out', ['cdir'], None, False,
+ warning_disabled=True, scan=copy_scan())
+ self.assertIn("Must specify either output or output_dirs, not both",
+ str(exc.exception))
+
+ def check_output_dirs(self, instantiate):
+ # Remove the directory so that files from other tests are not there
+ tools._RemoveOutputDir()
+ tools.PrepareOutputDir(None)
+
+ # This should create the .dts and .dtb in the output directory
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ outdir = tools.GetOutputDir()
+ fnames = glob.glob(outdir + '/*')
+ self.assertEqual(2, len(fnames))
+
+ dtb_platdata.run_steps(
+ ['all'], dtb_file, False, None, [outdir], None, instantiate,
+ warning_disabled=True, scan=copy_scan())
+ fnames = glob.glob(outdir + '/*')
+ return fnames
+
+ def test_output_dirs(self):
+ """Test outputting files to a directory"""
+ fnames = self.check_output_dirs(False)
+ self.assertEqual(5, len(fnames))
+
+ leafs = set(os.path.basename(fname) for fname in fnames)
+ self.assertEqual(
+ {'dt-structs-gen.h', 'source.dts', 'dt-plat.c', 'source.dtb',
+ 'dt-decl.h'},
+ leafs)
+
+ def test_output_dirs_inst(self):
+ """Test outputting files to a directory with instantiation"""
+ fnames = self.check_output_dirs(True)
+ self.assertEqual(6, len(fnames))
+
+ leafs = set(os.path.basename(fname) for fname in fnames)
+ self.assertEqual(
+ {'dt-structs-gen.h', 'source.dts', 'source.dtb',
+ 'dt-uclass.c', 'dt-decl.h', 'dt-device.c'},
+ leafs)
+
+ def setup_process_test(self):
+ """Set up a test of process_nodes()
+
+ This uses saved_scan but returns a deep copy of it, so it is safe to
+ modify it in these tests
+
+ Returns:
+ tuple:
+ DtbPlatdata: object to test
+ Scanner: scanner to use
+ """
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+
+ # Take a copy before messing with it
+ scan = copy_scan()
+ plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
+ plat.scan_dtb()
+ plat.scan_tree(False)
+ plat.prepare_nodes()
+ return plat, scan
+
+ def test_process_nodes(self):
+ """Test processing nodes to add various info"""
+ plat, scan = self.setup_process_test()
+ plat.process_nodes(True)
+
+ i2c_node = plat._fdt.GetNode('/i2c@0')
+ pmic_node = plat._fdt.GetNode('/i2c@0/pmic@9')
+ pmic = scan._drivers['sandbox_pmic']
+ i2c = scan._drivers['sandbox_i2c']
+ self.assertEqual('DM_DEVICE_REF(pmic_at_9)', pmic_node.dev_ref)
+ self.assertEqual(pmic, pmic_node.driver)
+ self.assertEqual(i2c_node, pmic_node.parent)
+ self.assertEqual(i2c, pmic_node.parent_driver)
+
+ # The pmic is the only child
+ self.assertEqual(pmic_node.parent_seq, 0)
+ self.assertEqual([pmic_node], i2c_node.child_devs)
+
+ # Start and end of the list should be the child_head
+ ref = '&DM_DEVICE_REF(i2c_at_0)->child_head'
+ self.assertEqual(
+ {-1: ref, 0: '&DM_DEVICE_REF(pmic_at_9)->sibling_node', 1: ref},
+ i2c_node.child_refs)
+
+ def test_process_nodes_bad_parent(self):
+ # Pretend that i2c has a parent (the pmic) and delete that driver
+ plat, scan = self.setup_process_test()
+
+ i2c_node = plat._fdt.GetNode('/i2c@0')
+ pmic_node = plat._fdt.GetNode('/i2c@0/pmic@9')
+ del scan._drivers['sandbox_pmic']
+ i2c_node.parent = pmic_node
+
+ # Process twice, the second time to generate an exception
+ plat.process_nodes(False)
+ with self.assertRaises(ValueError) as exc:
+ plat.process_nodes(True)
+ self.assertIn(
+ "Cannot parse/find parent driver 'sandbox_pmic' for 'sandbox_i2c",
+ str(exc.exception))
+
+ def test_process_nodes_bad_node(self):
+ plat, scan = self.setup_process_test()
+
+ # Now remove the pmic driver
+ del scan._drivers['sandbox_pmic']
+
+ # Process twice, the second time to generate an exception
+ plat.process_nodes(False)
+ with self.assertRaises(ValueError) as exc:
+ plat.process_nodes(True)
+ self.assertIn("Cannot parse/find driver for 'sandbox_pmic",
+ str(exc.exception))
+
+ def test_process_nodes_bad_uclass(self):
+ plat, scan = self.setup_process_test()
+
+ self.assertIn('UCLASS_I2C', scan._uclass)
+ del scan._uclass['UCLASS_I2C']
+ with self.assertRaises(ValueError) as exc:
+ plat.process_nodes(True)
+ self.assertIn("Cannot parse/find uclass 'UCLASS_I2C' for driver 'sandbox_i2c'",
+ str(exc.exception))
+
+ def test_process_nodes_used(self):
+ """Test processing nodes to add various info"""
+ plat, scan = self.setup_process_test()
+ plat.process_nodes(True)
+
+ pmic = scan._drivers['sandbox_pmic']
+ self.assertTrue(pmic.used)
+
+ gpio = scan._drivers['sandbox_gpio']
+ self.assertFalse(gpio.used)
+
+ def test_alias_read(self):
+ """Test obtaining aliases"""
+ dtb_file = get_dtb_file('dtoc_test_inst.dts')
+ output = tools.GetOutputFilename('output')
+ plat = self.run_test(['struct'], dtb_file, output)
+
+ scan = plat._scan
+ testfdt_node = plat._fdt.GetNode('/some-bus/test')
+ test0_node = plat._fdt.GetNode('/some-bus/test0')
+ self.assertIn('UCLASS_TEST_FDT', scan._uclass)
+ uc = scan._uclass['UCLASS_TEST_FDT']
+ self.assertEqual({1: testfdt_node, 2: test0_node},
+ uc.alias_num_to_node)
+ self.assertEqual({'/some-bus/test': 1, '/some-bus/test0': 2},
+ uc.alias_path_to_num)
+
+ # Try adding an alias that doesn't exist
+ self.assertFalse(scan.add_uclass_alias('fred', 3, None))
+
+ # Try adding an alias for a missing node
+ self.assertIsNone(scan.add_uclass_alias('testfdt', 3, None))
+
+ def test_alias_read_bad(self):
+ """Test invalid alias property name"""
+ dtb_file = get_dtb_file('dtoc_test_alias_bad.dts')
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ plat = self.run_test(['struct'], dtb_file, output)
+ self.assertIn("Cannot decode alias 'i2c4-'", str(exc.exception))
+
+ def test_alias_read_bad_path(self):
+ """Test alias pointing to a non-existent node"""
+ # This line may produce a warning, so capture it:
+ # Warning (alias_paths): /aliases:i2c4: aliases property is not a valid
+ # node (/does/not/exist)
+ dtb_file = get_dtb_file('dtoc_test_alias_bad_path.dts', True)
+
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ plat = self.run_test(['struct'], dtb_file, output)
+ self.assertIn("Alias 'i2c4' path '/does/not/exist' not found",
+ str(exc.exception))
+
+ def test_alias_read_bad_uclass(self):
+ """Test alias for a uclass that doesn't exist"""
+ dtb_file = get_dtb_file('dtoc_test_alias_bad_uc.dts')
+ output = tools.GetOutputFilename('output')
+ with test_util.capture_sys_output() as (stdout, _):
+ plat = self.run_test(['struct'], dtb_file, output)
+ self.assertEqual("Could not find uclass for alias 'other1'",
+ stdout.getvalue().strip())
+
+ def test_sequence(self):
+ """Test assignment of sequence numnbers"""
+ dtb_file = get_dtb_file('dtoc_test_inst.dts')
+ output = tools.GetOutputFilename('output')
+ plat = self.run_test(['struct'], dtb_file, output)
+
+ scan = plat._scan
+ testfdt = plat._fdt.GetNode('/some-bus/test')
+ self.assertEqual(1, testfdt.seq)
+ i2c = plat._fdt.GetNode('/i2c')
+
+ # For now this uclass is not compiled in, so no sequence is assigned
+ self.assertEqual(4, i2c.seq)
+ spl = plat._fdt.GetNode('/spl-test')
+ self.assertEqual(0, spl.seq)
+
+ def test_process_root(self):
+ """Test assignment of sequence numnbers"""
+ dtb_file = get_dtb_file('dtoc_test_simple.dts')
+ output = tools.GetOutputFilename('output')
+
+ # Take a copy before messing with it
+ scan = copy_scan()
+ plat = dtb_platdata.DtbPlatdata(scan, dtb_file, False)
+ plat.scan_dtb()
+ root = plat._fdt.GetRoot()
+
+ plat.scan_tree(False)
+ self.assertNotIn(root, plat._valid_nodes)
+
+ plat.scan_tree(True)
+ self.assertIn(root, plat._valid_nodes)
+ self.assertEqual('root_driver',
+ scan.get_normalized_compat_name(root)[0])
+
+ def test_simple_inst(self):
+ """Test output from some simple nodes with instantiate enabled"""
+ dtb_file = get_dtb_file('dtoc_test_inst.dts')
+ output = tools.GetOutputFilename('output')
+
+ self.run_test(['decl'], dtb_file, output, True)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.decl_text_inst, data)
+
+ self.run_test(['uclass'], dtb_file, output, True)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(UCLASS_HEADER_COMMON + self.uclass_text_inst, data)
+
+ self.run_test(['device'], dtb_file, output, True)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(self.device_text_inst, data)
+
+ def test_inst_no_hdr(self):
+ """Test dealing with a struct tsssshat has no header"""
+ dtb_file = get_dtb_file('dtoc_test_inst.dts')
+ output = tools.GetOutputFilename('output')
+
+ # Run it once to set everything up
+ plat = self.run_test(['decl'], dtb_file, output, True)
+ scan = plat._scan
+
+ # Restart the output file and delete any record of the uclass' struct
+ plat.setup_output(Ftype.SOURCE, output)
+ del scan._structs['dm_test_uc_priv']
+
+ # Now generate the uclasses, which should provide a warning
+ with test_util.capture_sys_output() as (stdout, _):
+ plat.generate_uclasses()
+ self.assertEqual(
+ 'Warning: Cannot find header file for struct dm_test_uc_priv',
+ stdout.getvalue().strip())
+
+ def test_missing_props(self):
+ """Test detection of a parent node with no properties"""
+ dtb_file = get_dtb_file('dtoc_test_noprops.dts', capture_stderr=True)
+ output = tools.GetOutputFilename('output')
+ with self.assertRaises(ValueError) as exc:
+ self.run_test(['struct'], dtb_file, output)
+ self.assertIn("Parent node '/i2c@0' has no properties - do you need",
+ str(exc.exception))
+
+ def test_single_reg(self):
+ """Test detection of a parent node with no properties"""
+ dtb_file = get_dtb_file('dtoc_test_single_reg.dts')
+ output = tools.GetOutputFilename('output')
+ self.run_test(['struct'], dtb_file, output)
diff --git a/roms/u-boot/tools/dtoc/test_fdt b/roms/u-boot/tools/dtoc/test_fdt
new file mode 120000
index 000000000..7c3b23031
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test_fdt
@@ -0,0 +1 @@
+test_fdt.py \ No newline at end of file
diff --git a/roms/u-boot/tools/dtoc/test_fdt.py b/roms/u-boot/tools/dtoc/test_fdt.py
new file mode 100755
index 000000000..856392b1b
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test_fdt.py
@@ -0,0 +1,696 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+from optparse import OptionParser
+import glob
+import os
+import shutil
+import sys
+import tempfile
+import unittest
+
+# Bring in the patman libraries
+our_path = os.path.dirname(os.path.realpath(__file__))
+sys.path.insert(1, os.path.join(our_path, '..'))
+
+from dtoc import fdt
+from dtoc import fdt_util
+from dtoc.fdt_util import fdt32_to_cpu
+from fdt import Type, BytesToValue
+import libfdt
+from patman import command
+from patman import test_util
+from patman import tools
+
+def _GetPropertyValue(dtb, node, prop_name):
+ """Low-level function to get the property value based on its offset
+
+ This looks directly in the device tree at the property's offset to find
+ its value. It is useful as a check that the property is in the correct
+ place.
+
+ Args:
+ node: Node to look in
+ prop_name: Property name to find
+
+ Returns:
+ Tuple:
+ Prop object found
+ Value of property as a string (found using property offset)
+ """
+ prop = node.props[prop_name]
+
+ # Add 12, which is sizeof(struct fdt_property), to get to start of data
+ offset = prop.GetOffset() + 12
+ data = dtb.GetContents()[offset:offset + len(prop.value)]
+ return prop, [chr(x) for x in data]
+
+def find_dtb_file(dts_fname):
+ """Locate a test file in the test/ directory
+
+ Args:
+ dts_fname (str): Filename to find, e.g. 'dtoc_test_simple.dts]
+
+ Returns:
+ str: Path to the test filename
+ """
+ return os.path.join('tools/dtoc/test', dts_fname)
+
+
+class TestFdt(unittest.TestCase):
+ """Tests for the Fdt module
+
+ This includes unit tests for some functions and functional tests for the fdt
+ module.
+ """
+ @classmethod
+ def setUpClass(cls):
+ tools.PrepareOutputDir(None)
+
+ @classmethod
+ def tearDownClass(cls):
+ tools.FinaliseOutputDir()
+
+ def setUp(self):
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
+
+ def testFdt(self):
+ """Test that we can open an Fdt"""
+ self.dtb.Scan()
+ root = self.dtb.GetRoot()
+ self.assertTrue(isinstance(root, fdt.Node))
+
+ def testGetNode(self):
+ """Test the GetNode() method"""
+ node = self.dtb.GetNode('/spl-test')
+ self.assertTrue(isinstance(node, fdt.Node))
+
+ node = self.dtb.GetNode('/i2c@0/pmic@9')
+ self.assertTrue(isinstance(node, fdt.Node))
+ self.assertEqual('pmic@9', node.name)
+ self.assertIsNone(self.dtb.GetNode('/i2c@0/pmic@9/missing'))
+
+ node = self.dtb.GetNode('/')
+ self.assertTrue(isinstance(node, fdt.Node))
+ self.assertEqual(0, node.Offset())
+
+ def testFlush(self):
+ """Check that we can flush the device tree out to its file"""
+ fname = self.dtb._fname
+ with open(fname, 'rb') as fd:
+ data = fd.read()
+ os.remove(fname)
+ with self.assertRaises(IOError):
+ open(fname, 'rb')
+ self.dtb.Flush()
+ with open(fname, 'rb') as fd:
+ data = fd.read()
+
+ def testPack(self):
+ """Test that packing a device tree works"""
+ self.dtb.Pack()
+
+ def testGetFdt(self):
+ """Tetst that we can access the raw device-tree data"""
+ self.assertTrue(isinstance(self.dtb.GetContents(), bytearray))
+
+ def testGetProps(self):
+ """Tests obtaining a list of properties"""
+ node = self.dtb.GetNode('/spl-test')
+ props = self.dtb.GetProps(node)
+ self.assertEqual(['boolval', 'bytearray', 'byteval', 'compatible',
+ 'intarray', 'intval', 'longbytearray', 'notstring',
+ 'stringarray', 'stringval', 'u-boot,dm-pre-reloc'],
+ sorted(props.keys()))
+
+ def testCheckError(self):
+ """Tests the ChecKError() function"""
+ with self.assertRaises(ValueError) as e:
+ fdt.CheckErr(-libfdt.NOTFOUND, 'hello')
+ self.assertIn('FDT_ERR_NOTFOUND: hello', str(e.exception))
+
+ def testGetFdt(self):
+ node = self.dtb.GetNode('/spl-test')
+ self.assertEqual(self.dtb, node.GetFdt())
+
+ def testBytesToValue(self):
+ self.assertEqual(BytesToValue(b'this\0is\0'),
+ (Type.STRING, ['this', 'is']))
+
+class TestNode(unittest.TestCase):
+ """Test operation of the Node class"""
+
+ @classmethod
+ def setUpClass(cls):
+ tools.PrepareOutputDir(None)
+
+ @classmethod
+ def tearDownClass(cls):
+ tools.FinaliseOutputDir()
+
+ def setUp(self):
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
+ self.node = self.dtb.GetNode('/spl-test')
+ self.fdt = self.dtb.GetFdtObj()
+
+ def testOffset(self):
+ """Tests that we can obtain the offset of a node"""
+ self.assertTrue(self.node.Offset() > 0)
+
+ def testDelete(self):
+ """Tests that we can delete a property"""
+ node2 = self.dtb.GetNode('/spl-test2')
+ offset1 = node2.Offset()
+ self.node.DeleteProp('intval')
+ offset2 = node2.Offset()
+ self.assertTrue(offset2 < offset1)
+ self.node.DeleteProp('intarray')
+ offset3 = node2.Offset()
+ self.assertTrue(offset3 < offset2)
+ with self.assertRaises(libfdt.FdtException):
+ self.node.DeleteProp('missing')
+
+ def testDeleteGetOffset(self):
+ """Test that property offset update when properties are deleted"""
+ self.node.DeleteProp('intval')
+ prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
+ self.assertEqual(prop.value, value)
+
+ def testFindNode(self):
+ """Tests that we can find a node using the FindNode() functoin"""
+ node = self.dtb.GetRoot().FindNode('i2c@0')
+ self.assertEqual('i2c@0', node.name)
+ subnode = node.FindNode('pmic@9')
+ self.assertEqual('pmic@9', subnode.name)
+ self.assertEqual(None, node.FindNode('missing'))
+
+ def testRefreshMissingNode(self):
+ """Test refreshing offsets when an extra node is present in dtb"""
+ # Delete it from our tables, not the device tree
+ del self.dtb._root.subnodes[-1]
+ with self.assertRaises(ValueError) as e:
+ self.dtb.Refresh()
+ self.assertIn('Internal error, offset', str(e.exception))
+
+ def testRefreshExtraNode(self):
+ """Test refreshing offsets when an expected node is missing"""
+ # Delete it from the device tre, not our tables
+ self.fdt.del_node(self.node.Offset())
+ with self.assertRaises(ValueError) as e:
+ self.dtb.Refresh()
+ self.assertIn('Internal error, node name mismatch '
+ 'spl-test != spl-test2', str(e.exception))
+
+ def testRefreshMissingProp(self):
+ """Test refreshing offsets when an extra property is present in dtb"""
+ # Delete it from our tables, not the device tree
+ del self.node.props['notstring']
+ with self.assertRaises(ValueError) as e:
+ self.dtb.Refresh()
+ self.assertIn("Internal error, node '/spl-test' property 'notstring' missing, offset ",
+ str(e.exception))
+
+ def testLookupPhandle(self):
+ """Test looking up a single phandle"""
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
+ node = dtb.GetNode('/phandle-source2')
+ prop = node.props['clocks']
+ target = dtb.GetNode('/phandle-target')
+ self.assertEqual(target, dtb.LookupPhandle(fdt32_to_cpu(prop.value)))
+
+ def testAddNodeSpace(self):
+ """Test adding a single node when out of space"""
+ self.fdt.pack()
+ self.node.AddSubnode('subnode')
+ with self.assertRaises(libfdt.FdtException) as e:
+ self.dtb.Sync(auto_resize=False)
+ self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
+
+ self.dtb.Sync(auto_resize=True)
+ offset = self.fdt.path_offset('/spl-test/subnode')
+ self.assertTrue(offset > 0)
+
+ def testAddNodes(self):
+ """Test adding various subnode and properies"""
+ node = self.dtb.GetNode('/i2c@0')
+
+ # Add one more node next to the pmic one
+ sn1 = node.AddSubnode('node-one')
+ sn1.AddInt('integer-a', 12)
+ sn1.AddInt('integer-b', 23)
+
+ # Sync so that everything is clean
+ self.dtb.Sync(auto_resize=True)
+
+ # Add two subnodes next to pmic and node-one
+ sn2 = node.AddSubnode('node-two')
+ sn2.AddInt('integer-2a', 34)
+ sn2.AddInt('integer-2b', 45)
+
+ sn3 = node.AddSubnode('node-three')
+ sn3.AddInt('integer-3', 123)
+
+ # Add a property to the node after i2c@0 to check that this is not
+ # disturbed by adding a subnode to i2c@0
+ orig_node = self.dtb.GetNode('/orig-node')
+ orig_node.AddInt('integer-4', 456)
+
+ # Add a property to the pmic node to check that pmic properties are not
+ # disturbed
+ pmic = self.dtb.GetNode('/i2c@0/pmic@9')
+ pmic.AddInt('integer-5', 567)
+
+ self.dtb.Sync(auto_resize=True)
+
+ def testRefreshNameMismatch(self):
+ """Test name mismatch when syncing nodes and properties"""
+ prop = self.node.AddInt('integer-a', 12)
+
+ wrong_offset = self.dtb.GetNode('/i2c@0')._offset
+ self.node._offset = wrong_offset
+ with self.assertRaises(ValueError) as e:
+ self.dtb.Sync()
+ self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
+ str(e.exception))
+
+ with self.assertRaises(ValueError) as e:
+ self.node.Refresh(wrong_offset)
+ self.assertIn("Internal error, node '/spl-test' name mismatch 'i2c@0'",
+ str(e.exception))
+
+
+class TestProp(unittest.TestCase):
+ """Test operation of the Prop class"""
+
+ @classmethod
+ def setUpClass(cls):
+ tools.PrepareOutputDir(None)
+
+ @classmethod
+ def tearDownClass(cls):
+ tools.FinaliseOutputDir()
+
+ def setUp(self):
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
+ self.node = self.dtb.GetNode('/spl-test')
+ self.fdt = self.dtb.GetFdtObj()
+
+ def testMissingNode(self):
+ self.assertEqual(None, self.dtb.GetNode('missing'))
+
+ def testPhandle(self):
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
+ node = dtb.GetNode('/phandle-source2')
+ prop = node.props['clocks']
+ self.assertTrue(fdt32_to_cpu(prop.value) > 0)
+
+ def _ConvertProp(self, prop_name):
+ """Helper function to look up a property in self.node and return it
+
+ Args:
+ Property name to find
+
+ Return fdt.Prop object for this property
+ """
+ p = self.fdt.getprop(self.node.Offset(), prop_name)
+ return fdt.Prop(self.node, -1, prop_name, p)
+
+ def testMakeProp(self):
+ """Test we can convert all the the types that are supported"""
+ prop = self._ConvertProp('boolval')
+ self.assertEqual(Type.BOOL, prop.type)
+ self.assertEqual(True, prop.value)
+
+ prop = self._ConvertProp('intval')
+ self.assertEqual(Type.INT, prop.type)
+ self.assertEqual(1, fdt32_to_cpu(prop.value))
+
+ prop = self._ConvertProp('intarray')
+ self.assertEqual(Type.INT, prop.type)
+ val = [fdt32_to_cpu(val) for val in prop.value]
+ self.assertEqual([2, 3, 4], val)
+
+ prop = self._ConvertProp('byteval')
+ self.assertEqual(Type.BYTE, prop.type)
+ self.assertEqual(5, ord(prop.value))
+
+ prop = self._ConvertProp('longbytearray')
+ self.assertEqual(Type.BYTE, prop.type)
+ val = [ord(val) for val in prop.value]
+ self.assertEqual([9, 10, 11, 12, 13, 14, 15, 16, 17], val)
+
+ prop = self._ConvertProp('stringval')
+ self.assertEqual(Type.STRING, prop.type)
+ self.assertEqual('message', prop.value)
+
+ prop = self._ConvertProp('stringarray')
+ self.assertEqual(Type.STRING, prop.type)
+ self.assertEqual(['multi-word', 'message'], prop.value)
+
+ prop = self._ConvertProp('notstring')
+ self.assertEqual(Type.BYTE, prop.type)
+ val = [ord(val) for val in prop.value]
+ self.assertEqual([0x20, 0x21, 0x22, 0x10, 0], val)
+
+ def testGetEmpty(self):
+ """Tests the GetEmpty() function for the various supported types"""
+ self.assertEqual(True, fdt.Prop.GetEmpty(Type.BOOL))
+ self.assertEqual(chr(0), fdt.Prop.GetEmpty(Type.BYTE))
+ self.assertEqual(tools.GetBytes(0, 4), fdt.Prop.GetEmpty(Type.INT))
+ self.assertEqual('', fdt.Prop.GetEmpty(Type.STRING))
+
+ def testGetOffset(self):
+ """Test we can get the offset of a property"""
+ prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
+ self.assertEqual(prop.value, value)
+
+ def testWiden(self):
+ """Test widening of values"""
+ node2 = self.dtb.GetNode('/spl-test2')
+ node3 = self.dtb.GetNode('/spl-test3')
+ prop = self.node.props['intval']
+
+ # No action
+ prop2 = node2.props['intval']
+ prop.Widen(prop2)
+ self.assertEqual(Type.INT, prop.type)
+ self.assertEqual(1, fdt32_to_cpu(prop.value))
+
+ # Convert singla value to array
+ prop2 = self.node.props['intarray']
+ prop.Widen(prop2)
+ self.assertEqual(Type.INT, prop.type)
+ self.assertTrue(isinstance(prop.value, list))
+
+ # A 4-byte array looks like a single integer. When widened by a longer
+ # byte array, it should turn into an array.
+ prop = self.node.props['longbytearray']
+ prop2 = node2.props['longbytearray']
+ prop3 = node3.props['longbytearray']
+ self.assertFalse(isinstance(prop2.value, list))
+ self.assertEqual(4, len(prop2.value))
+ self.assertEqual(b'\x09\x0a\x0b\x0c', prop2.value)
+ prop2.Widen(prop)
+ self.assertTrue(isinstance(prop2.value, list))
+ self.assertEqual(9, len(prop2.value))
+ self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\0',
+ '\0', '\0', '\0', '\0'], prop2.value)
+ prop3.Widen(prop)
+ self.assertTrue(isinstance(prop3.value, list))
+ self.assertEqual(9, len(prop3.value))
+ self.assertEqual(['\x09', '\x0a', '\x0b', '\x0c', '\x0d',
+ '\x0e', '\x0f', '\x10', '\0'], prop3.value)
+
+ # Similarly for a string array
+ prop = self.node.props['stringval']
+ prop2 = node2.props['stringarray']
+ self.assertFalse(isinstance(prop.value, list))
+ self.assertEqual(7, len(prop.value))
+ prop.Widen(prop2)
+ self.assertTrue(isinstance(prop.value, list))
+ self.assertEqual(3, len(prop.value))
+
+ # Enlarging an existing array
+ prop = self.node.props['stringarray']
+ prop2 = node2.props['stringarray']
+ self.assertTrue(isinstance(prop.value, list))
+ self.assertEqual(2, len(prop.value))
+ prop.Widen(prop2)
+ self.assertTrue(isinstance(prop.value, list))
+ self.assertEqual(3, len(prop.value))
+
+ def testAdd(self):
+ """Test adding properties"""
+ self.fdt.pack()
+ # This function should automatically expand the device tree
+ self.node.AddZeroProp('one')
+ self.node.AddZeroProp('two')
+ self.node.AddZeroProp('three')
+ self.dtb.Sync(auto_resize=True)
+
+ # Updating existing properties should be OK, since the device-tree size
+ # does not change
+ self.fdt.pack()
+ self.node.SetInt('one', 1)
+ self.node.SetInt('two', 2)
+ self.node.SetInt('three', 3)
+ self.dtb.Sync(auto_resize=False)
+
+ # This should fail since it would need to increase the device-tree size
+ self.node.AddZeroProp('four')
+ with self.assertRaises(libfdt.FdtException) as e:
+ self.dtb.Sync(auto_resize=False)
+ self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
+ self.dtb.Sync(auto_resize=True)
+
+ def testAddMore(self):
+ """Test various other methods for adding and setting properties"""
+ self.node.AddZeroProp('one')
+ self.dtb.Sync(auto_resize=True)
+ data = self.fdt.getprop(self.node.Offset(), 'one')
+ self.assertEqual(0, fdt32_to_cpu(data))
+
+ self.node.SetInt('one', 1)
+ self.dtb.Sync(auto_resize=False)
+ data = self.fdt.getprop(self.node.Offset(), 'one')
+ self.assertEqual(1, fdt32_to_cpu(data))
+
+ val = 1234
+ self.node.AddInt('integer', val)
+ self.dtb.Sync(auto_resize=True)
+ data = self.fdt.getprop(self.node.Offset(), 'integer')
+ self.assertEqual(val, fdt32_to_cpu(data))
+
+ val = '123' + chr(0) + '456'
+ self.node.AddString('string', val)
+ self.dtb.Sync(auto_resize=True)
+ data = self.fdt.getprop(self.node.Offset(), 'string')
+ self.assertEqual(tools.ToBytes(val) + b'\0', data)
+
+ self.fdt.pack()
+ self.node.SetString('string', val + 'x')
+ with self.assertRaises(libfdt.FdtException) as e:
+ self.dtb.Sync(auto_resize=False)
+ self.assertIn('FDT_ERR_NOSPACE', str(e.exception))
+ self.node.SetString('string', val[:-1])
+
+ prop = self.node.props['string']
+ prop.SetData(tools.ToBytes(val))
+ self.dtb.Sync(auto_resize=False)
+ data = self.fdt.getprop(self.node.Offset(), 'string')
+ self.assertEqual(tools.ToBytes(val), data)
+
+ self.node.AddEmptyProp('empty', 5)
+ self.dtb.Sync(auto_resize=True)
+ prop = self.node.props['empty']
+ prop.SetData(tools.ToBytes(val))
+ self.dtb.Sync(auto_resize=False)
+ data = self.fdt.getprop(self.node.Offset(), 'empty')
+ self.assertEqual(tools.ToBytes(val), data)
+
+ self.node.SetData('empty', b'123')
+ self.assertEqual(b'123', prop.bytes)
+
+ # Trying adding a lot of data at once
+ self.node.AddData('data', tools.GetBytes(65, 20000))
+ self.dtb.Sync(auto_resize=True)
+
+ def testFromData(self):
+ dtb2 = fdt.Fdt.FromData(self.dtb.GetContents())
+ self.assertEqual(dtb2.GetContents(), self.dtb.GetContents())
+
+ self.node.AddEmptyProp('empty', 5)
+ self.dtb.Sync(auto_resize=True)
+ self.assertTrue(dtb2.GetContents() != self.dtb.GetContents())
+
+ def testMissingSetInt(self):
+ """Test handling of a missing property with SetInt"""
+ with self.assertRaises(ValueError) as e:
+ self.node.SetInt('one', 1)
+ self.assertIn("node '/spl-test': Missing property 'one'",
+ str(e.exception))
+
+ def testMissingSetData(self):
+ """Test handling of a missing property with SetData"""
+ with self.assertRaises(ValueError) as e:
+ self.node.SetData('one', b'data')
+ self.assertIn("node '/spl-test': Missing property 'one'",
+ str(e.exception))
+
+ def testMissingSetString(self):
+ """Test handling of a missing property with SetString"""
+ with self.assertRaises(ValueError) as e:
+ self.node.SetString('one', 1)
+ self.assertIn("node '/spl-test': Missing property 'one'",
+ str(e.exception))
+
+ def testGetFilename(self):
+ """Test the dtb filename can be provided"""
+ self.assertEqual(tools.GetOutputFilename('source.dtb'),
+ self.dtb.GetFilename())
+
+
+class TestFdtUtil(unittest.TestCase):
+ """Tests for the fdt_util module
+
+ This module will likely be mostly replaced at some point, once upstream
+ libfdt has better Python support. For now, this provides tests for current
+ functionality.
+ """
+ @classmethod
+ def setUpClass(cls):
+ tools.PrepareOutputDir(None)
+
+ @classmethod
+ def tearDownClass(cls):
+ tools.FinaliseOutputDir()
+
+ def setUp(self):
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
+ self.node = self.dtb.GetNode('/spl-test')
+
+ def testGetInt(self):
+ self.assertEqual(1, fdt_util.GetInt(self.node, 'intval'))
+ self.assertEqual(3, fdt_util.GetInt(self.node, 'missing', 3))
+
+ with self.assertRaises(ValueError) as e:
+ self.assertEqual(3, fdt_util.GetInt(self.node, 'intarray'))
+ self.assertIn("property 'intarray' has list value: expecting a single "
+ 'integer', str(e.exception))
+
+ def testGetString(self):
+ self.assertEqual('message', fdt_util.GetString(self.node, 'stringval'))
+ self.assertEqual('test', fdt_util.GetString(self.node, 'missing',
+ 'test'))
+
+ with self.assertRaises(ValueError) as e:
+ self.assertEqual(3, fdt_util.GetString(self.node, 'stringarray'))
+ self.assertIn("property 'stringarray' has list value: expecting a "
+ 'single string', str(e.exception))
+
+ def testGetBool(self):
+ self.assertEqual(True, fdt_util.GetBool(self.node, 'boolval'))
+ self.assertEqual(False, fdt_util.GetBool(self.node, 'missing'))
+ self.assertEqual(True, fdt_util.GetBool(self.node, 'missing', True))
+ self.assertEqual(False, fdt_util.GetBool(self.node, 'missing', False))
+
+ def testGetByte(self):
+ self.assertEqual(5, fdt_util.GetByte(self.node, 'byteval'))
+ self.assertEqual(3, fdt_util.GetByte(self.node, 'missing', 3))
+
+ with self.assertRaises(ValueError) as e:
+ fdt_util.GetByte(self.node, 'longbytearray')
+ self.assertIn("property 'longbytearray' has list value: expecting a "
+ 'single byte', str(e.exception))
+
+ with self.assertRaises(ValueError) as e:
+ fdt_util.GetByte(self.node, 'intval')
+ self.assertIn("property 'intval' has length 4, expecting 1",
+ str(e.exception))
+
+ def testGetPhandleList(self):
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
+ node = dtb.GetNode('/phandle-source2')
+ self.assertEqual([1], fdt_util.GetPhandleList(node, 'clocks'))
+ node = dtb.GetNode('/phandle-source')
+ self.assertEqual([1, 2, 11, 3, 12, 13, 1],
+ fdt_util.GetPhandleList(node, 'clocks'))
+ self.assertEqual(None, fdt_util.GetPhandleList(node, 'missing'))
+
+ def testGetDataType(self):
+ self.assertEqual(1, fdt_util.GetDatatype(self.node, 'intval', int))
+ self.assertEqual('message', fdt_util.GetDatatype(self.node, 'stringval',
+ str))
+ with self.assertRaises(ValueError) as e:
+ self.assertEqual(3, fdt_util.GetDatatype(self.node, 'boolval',
+ bool))
+ def testFdtCellsToCpu(self):
+ val = self.node.props['intarray'].value
+ self.assertEqual(0, fdt_util.fdt_cells_to_cpu(val, 0))
+ self.assertEqual(2, fdt_util.fdt_cells_to_cpu(val, 1))
+
+ dtb2 = fdt.FdtScan(find_dtb_file('dtoc_test_addr64.dts'))
+ node1 = dtb2.GetNode('/test1')
+ val = node1.props['reg'].value
+ self.assertEqual(0x1234, fdt_util.fdt_cells_to_cpu(val, 2))
+
+ node2 = dtb2.GetNode('/test2')
+ val = node2.props['reg'].value
+ self.assertEqual(0x1234567890123456, fdt_util.fdt_cells_to_cpu(val, 2))
+ self.assertEqual(0x9876543210987654, fdt_util.fdt_cells_to_cpu(val[2:],
+ 2))
+ self.assertEqual(0x12345678, fdt_util.fdt_cells_to_cpu(val, 1))
+
+ def testEnsureCompiled(self):
+ """Test a degenerate case of this function (file already compiled)"""
+ dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
+ self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
+
+ def testEnsureCompiledTmpdir(self):
+ """Test providing a temporary directory"""
+ try:
+ old_outdir = tools.outdir
+ tools.outdir= None
+ tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
+ dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
+ tmpdir)
+ self.assertEqual(tmpdir, os.path.dirname(dtb))
+ shutil.rmtree(tmpdir)
+ finally:
+ tools.outdir= old_outdir
+
+
+def RunTestCoverage():
+ """Run the tests and check that we get 100% coverage"""
+ test_util.RunTestCoverage('tools/dtoc/test_fdt.py', None,
+ ['tools/patman/*.py', '*test_fdt.py'], options.build_dir)
+
+
+def RunTests(args):
+ """Run all the test we have for the fdt model
+
+ Args:
+ args: List of positional args provided to fdt. This can hold a test
+ name to execute (as in 'fdt -t testFdt', for example)
+ """
+ result = unittest.TestResult()
+ sys.argv = [sys.argv[0]]
+ test_name = args and args[0] or None
+ for module in (TestFdt, TestNode, TestProp, TestFdtUtil):
+ if test_name:
+ try:
+ suite = unittest.TestLoader().loadTestsFromName(test_name, module)
+ except AttributeError:
+ continue
+ else:
+ suite = unittest.TestLoader().loadTestsFromTestCase(module)
+ suite.run(result)
+
+ print(result)
+ for _, err in result.errors:
+ print(err)
+ for _, err in result.failures:
+ print(err)
+
+if __name__ != '__main__':
+ sys.exit(1)
+
+parser = OptionParser()
+parser.add_option('-B', '--build-dir', type='string', default='b',
+ help='Directory containing the build output')
+parser.add_option('-P', '--processes', type=int,
+ help='set number of processes to use for running tests')
+parser.add_option('-t', '--test', action='store_true', dest='test',
+ default=False, help='run tests')
+parser.add_option('-T', '--test-coverage', action='store_true',
+ default=False, help='run tests and check for 100% coverage')
+(options, args) = parser.parse_args()
+
+# Run our meagre tests
+if options.test:
+ RunTests(args)
+elif options.test_coverage:
+ RunTestCoverage()
diff --git a/roms/u-boot/tools/dtoc/test_src_scan.py b/roms/u-boot/tools/dtoc/test_src_scan.py
new file mode 100644
index 000000000..d6da03849
--- /dev/null
+++ b/roms/u-boot/tools/dtoc/test_src_scan.py
@@ -0,0 +1,492 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2020 Google LLC
+#
+
+"""Tests for the src_scan module
+
+This includes unit tests for scanning of the source code
+"""
+
+import copy
+import os
+import shutil
+import tempfile
+import unittest
+from unittest import mock
+
+from dtoc import src_scan
+from patman import test_util
+from patman import tools
+
+OUR_PATH = os.path.dirname(os.path.realpath(__file__))
+
+class FakeNode:
+ """Fake Node object for testing"""
+ def __init__(self):
+ self.name = None
+ self.props = {}
+
+class FakeProp:
+ """Fake Prop object for testing"""
+ def __init__(self):
+ self.name = None
+ self.value = None
+
+# This is a test so is allowed to access private things in the module it is
+# testing
+# pylint: disable=W0212
+
+class TestSrcScan(unittest.TestCase):
+ """Tests for src_scan"""
+ @classmethod
+ def setUpClass(cls):
+ tools.PrepareOutputDir(None)
+
+ @classmethod
+ def tearDownClass(cls):
+ tools.FinaliseOutputDir()
+
+ def test_simple(self):
+ """Simple test of scanning drivers"""
+ scan = src_scan.Scanner(None, None)
+ scan.scan_drivers()
+ self.assertIn('sandbox_gpio', scan._drivers)
+ self.assertIn('sandbox_gpio_alias', scan._driver_aliases)
+ self.assertEqual('sandbox_gpio',
+ scan._driver_aliases['sandbox_gpio_alias'])
+ self.assertNotIn('sandbox_gpio_alias2', scan._driver_aliases)
+
+ def test_additional(self):
+ """Test with additional drivers to scan"""
+ scan = src_scan.Scanner(
+ None, [None, '', 'tools/dtoc/test/dtoc_test_scan_drivers.cxx'])
+ scan.scan_drivers()
+ self.assertIn('sandbox_gpio_alias2', scan._driver_aliases)
+ self.assertEqual('sandbox_gpio',
+ scan._driver_aliases['sandbox_gpio_alias2'])
+
+ def test_unicode_error(self):
+ """Test running dtoc with an invalid unicode file
+
+ To be able to perform this test without adding a weird text file which
+ would produce issues when using checkpatch.pl or patman, generate the
+ file at runtime and then process it.
+ """
+ driver_fn = '/tmp/' + next(tempfile._get_candidate_names())
+ with open(driver_fn, 'wb+') as fout:
+ fout.write(b'\x81')
+
+ scan = src_scan.Scanner(None, [driver_fn])
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.scan_drivers()
+ self.assertRegex(stdout.getvalue(),
+ r"Skipping file '.*' due to unicode error\s*")
+
+ def test_driver(self):
+ """Test the Driver class"""
+ i2c = 'I2C_UCLASS'
+ compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
+ 'rockchip,rk3288-srf': None}
+ drv1 = src_scan.Driver('fred', 'fred.c')
+ drv2 = src_scan.Driver('mary', 'mary.c')
+ drv3 = src_scan.Driver('fred', 'fred.c')
+ drv1.uclass_id = i2c
+ drv1.compat = compat
+ drv2.uclass_id = i2c
+ drv2.compat = compat
+ drv3.uclass_id = i2c
+ drv3.compat = compat
+ self.assertEqual(
+ "Driver(name='fred', used=False, uclass_id='I2C_UCLASS', "
+ "compat={'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF', "
+ "'rockchip,rk3288-srf': None}, priv=)", str(drv1))
+ self.assertEqual(drv1, drv3)
+ self.assertNotEqual(drv1, drv2)
+ self.assertNotEqual(drv2, drv3)
+
+ def test_scan_dirs(self):
+ """Test scanning of source directories"""
+ def add_file(fname):
+ pathname = os.path.join(indir, fname)
+ dirname = os.path.dirname(pathname)
+ os.makedirs(dirname, exist_ok=True)
+ tools.WriteFile(pathname, '', binary=False)
+ fname_list.append(pathname)
+
+ try:
+ indir = tempfile.mkdtemp(prefix='dtoc.')
+
+ fname_list = []
+ add_file('fname.c')
+ add_file('.git/ignoreme.c')
+ add_file('dir/fname2.c')
+ add_file('build-sandbox/ignoreme2.c')
+
+ # Mock out scan_driver and check that it is called with the
+ # expected files
+ with mock.patch.object(src_scan.Scanner, "scan_driver") as mocked:
+ scan = src_scan.Scanner(indir, None)
+ scan.scan_drivers()
+ self.assertEqual(2, len(mocked.mock_calls))
+ self.assertEqual(mock.call(fname_list[0]),
+ mocked.mock_calls[0])
+ # .git file should be ignored
+ self.assertEqual(mock.call(fname_list[2]),
+ mocked.mock_calls[1])
+ finally:
+ shutil.rmtree(indir)
+
+ def test_scan(self):
+ """Test scanning of a driver"""
+ fname = os.path.join(OUR_PATH, '..', '..', 'drivers/i2c/tegra_i2c.c')
+ buff = tools.ReadFile(fname, False)
+ scan = src_scan.Scanner(None, None)
+ scan._parse_driver(fname, buff)
+ self.assertIn('i2c_tegra', scan._drivers)
+ drv = scan._drivers['i2c_tegra']
+ self.assertEqual('i2c_tegra', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual(
+ {'nvidia,tegra114-i2c': 'TYPE_114',
+ 'nvidia,tegra20-i2c': 'TYPE_STD',
+ 'nvidia,tegra20-i2c-dvc': 'TYPE_DVC'}, drv.compat)
+ self.assertEqual('i2c_bus', drv.priv)
+ self.assertEqual(1, len(scan._drivers))
+
+ def test_normalized_name(self):
+ """Test operation of get_normalized_compat_name()"""
+ prop = FakeProp()
+ prop.name = 'compatible'
+ prop.value = 'rockchip,rk3288-grf'
+ node = FakeNode()
+ node.props = {'compatible': prop}
+
+ # get_normalized_compat_name() uses this to check for root node
+ node.parent = FakeNode()
+
+ scan = src_scan.Scanner(None, None)
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual([], aliases)
+ self.assertEqual(1, len(scan._missing_drivers))
+ self.assertEqual({'rockchip_rk3288_grf'}, scan._missing_drivers)
+ #'WARNING: the driver rockchip_rk3288_grf was not found in the driver list',
+ #stdout.getvalue().strip())
+
+ i2c = 'I2C_UCLASS'
+ compat = {'rockchip,rk3288-grf': 'ROCKCHIP_SYSCON_GRF',
+ 'rockchip,rk3288-srf': None}
+ drv = src_scan.Driver('fred', 'fred.c')
+ drv.uclass_id = i2c
+ drv.compat = compat
+ scan._drivers['rockchip_rk3288_grf'] = drv
+
+ scan._driver_aliases['rockchip_rk3288_srf'] = 'rockchip_rk3288_grf'
+
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('', stdout.getvalue().strip())
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual([], aliases)
+
+ prop.value = 'rockchip,rk3288-srf'
+ with test_util.capture_sys_output() as (stdout, _):
+ name, aliases = scan.get_normalized_compat_name(node)
+ self.assertEqual('', stdout.getvalue().strip())
+ self.assertEqual('rockchip_rk3288_grf', name)
+ self.assertEqual(['rockchip_rk3288_srf'], aliases)
+
+ def test_scan_errors(self):
+ """Test detection of scanning errors"""
+ buff = '''
+static const struct udevice_id tegra_i2c_ids2[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+ .name = "i2c_tegra",
+ .id = UCLASS_I2C,
+ .of_match = tegra_i2c_ids,
+};
+'''
+ scan = src_scan.Scanner(None, None)
+ with self.assertRaises(ValueError) as exc:
+ scan._parse_driver('file.c', buff)
+ self.assertIn(
+ "file.c: Unknown compatible var 'tegra_i2c_ids' (found: tegra_i2c_ids2)",
+ str(exc.exception))
+
+ def test_of_match(self):
+ """Test detection of of_match_ptr() member"""
+ buff = '''
+static const struct udevice_id tegra_i2c_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(i2c_tegra) = {
+ .name = "i2c_tegra",
+ .id = UCLASS_I2C,
+ .of_match = of_match_ptr(tegra_i2c_ids),
+};
+'''
+ scan = src_scan.Scanner(None, None)
+ scan._parse_driver('file.c', buff)
+ self.assertIn('i2c_tegra', scan._drivers)
+ drv = scan._drivers['i2c_tegra']
+ self.assertEqual('i2c_tegra', drv.name)
+ self.assertEqual('', drv.phase)
+ self.assertEqual([], drv.headers)
+
+ def test_priv(self):
+ """Test collection of struct info from drivers"""
+ buff = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(testing) = {
+ .name = "testing",
+ .id = UCLASS_I2C,
+ .of_match = test_ids,
+ .priv_auto = sizeof(struct some_priv),
+ .plat_auto = sizeof(struct some_plat),
+ .per_child_auto = sizeof(struct some_cpriv),
+ .per_child_plat_auto = sizeof(struct some_cplat),
+ DM_PHASE(tpl)
+ DM_HEADER(<i2c.h>)
+ DM_HEADER(<asm/clk.h>)
+};
+'''
+ scan = src_scan.Scanner(None, None)
+ scan._parse_driver('file.c', buff)
+ self.assertIn('testing', scan._drivers)
+ drv = scan._drivers['testing']
+ self.assertEqual('testing', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual(
+ {'nvidia,tegra114-i2c': 'TYPE_114'}, drv.compat)
+ self.assertEqual('some_priv', drv.priv)
+ self.assertEqual('some_plat', drv.plat)
+ self.assertEqual('some_cpriv', drv.child_priv)
+ self.assertEqual('some_cplat', drv.child_plat)
+ self.assertEqual('tpl', drv.phase)
+ self.assertEqual(['<i2c.h>', '<asm/clk.h>'], drv.headers)
+ self.assertEqual(1, len(scan._drivers))
+
+ def test_uclass_scan(self):
+ """Test collection of uclass-driver info"""
+ buff = '''
+UCLASS_DRIVER(i2c) = {
+ .id = UCLASS_I2C,
+ .name = "i2c",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .priv_auto = sizeof(struct some_priv),
+ .per_device_auto = sizeof(struct per_dev_priv),
+ .per_device_plat_auto = sizeof(struct per_dev_plat),
+ .per_child_auto = sizeof(struct per_child_priv),
+ .per_child_plat_auto = sizeof(struct per_child_plat),
+ .child_post_bind = i2c_child_post_bind,
+};
+
+'''
+ scan = src_scan.Scanner(None, None)
+ scan._parse_uclass_driver('file.c', buff)
+ self.assertIn('UCLASS_I2C', scan._uclass)
+ drv = scan._uclass['UCLASS_I2C']
+ self.assertEqual('i2c', drv.name)
+ self.assertEqual('UCLASS_I2C', drv.uclass_id)
+ self.assertEqual('some_priv', drv.priv)
+ self.assertEqual('per_dev_priv', drv.per_dev_priv)
+ self.assertEqual('per_dev_plat', drv.per_dev_plat)
+ self.assertEqual('per_child_priv', drv.per_child_priv)
+ self.assertEqual('per_child_plat', drv.per_child_plat)
+ self.assertEqual(1, len(scan._uclass))
+
+ drv2 = copy.deepcopy(drv)
+ self.assertEqual(drv, drv2)
+ drv2.priv = 'other_priv'
+ self.assertNotEqual(drv, drv2)
+
+ # The hashes only depend on the uclass ID, so should be equal
+ self.assertEqual(drv.__hash__(), drv2.__hash__())
+
+ self.assertEqual("UclassDriver(name='i2c', uclass_id='UCLASS_I2C')",
+ str(drv))
+
+ def test_uclass_scan_errors(self):
+ """Test detection of uclass scanning errors"""
+ buff = '''
+UCLASS_DRIVER(i2c) = {
+ .name = "i2c",
+};
+
+'''
+ scan = src_scan.Scanner(None, None)
+ with self.assertRaises(ValueError) as exc:
+ scan._parse_uclass_driver('file.c', buff)
+ self.assertIn("file.c: Cannot parse uclass ID in driver 'i2c'",
+ str(exc.exception))
+
+ def test_struct_scan(self):
+ """Test collection of struct info"""
+ buff = '''
+/* some comment */
+struct some_struct1 {
+ struct i2c_msg *msgs;
+ uint nmsgs;
+};
+'''
+ scan = src_scan.Scanner(None, None)
+ scan._basedir = os.path.join(OUR_PATH, '..', '..')
+ scan._parse_structs('arch/arm/include/asm/file.h', buff)
+ self.assertIn('some_struct1', scan._structs)
+ struc = scan._structs['some_struct1']
+ self.assertEqual('some_struct1', struc.name)
+ self.assertEqual('asm/file.h', struc.fname)
+
+ buff = '''
+/* another comment */
+struct another_struct {
+ int speed_hz;
+ int max_transaction_bytes;
+};
+'''
+ scan._parse_structs('include/file2.h', buff)
+ self.assertIn('another_struct', scan._structs)
+ struc = scan._structs['another_struct']
+ self.assertEqual('another_struct', struc.name)
+ self.assertEqual('file2.h', struc.fname)
+
+ self.assertEqual(2, len(scan._structs))
+
+ self.assertEqual("Struct(name='another_struct', fname='file2.h')",
+ str(struc))
+
+ def test_struct_scan_errors(self):
+ """Test scanning a header file with an invalid unicode file"""
+ output = tools.GetOutputFilename('output.h')
+ tools.WriteFile(output, b'struct this is a test \x81 of bad unicode')
+
+ scan = src_scan.Scanner(None, None)
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.scan_header(output)
+ self.assertIn('due to unicode error', stdout.getvalue())
+
+ def setup_dup_drivers(self, name, phase=''):
+ """Set up for a duplcate test
+
+ Returns:
+ tuple:
+ Scanner to use
+ Driver record for first driver
+ Text of second driver declaration
+ Node for driver 1
+ """
+ driver1 = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ { }
+};
+
+U_BOOT_DRIVER(%s) = {
+ .name = "testing",
+ .id = UCLASS_I2C,
+ .of_match = test_ids,
+ %s
+};
+''' % (name, 'DM_PHASE(%s)' % phase if phase else '')
+ driver2 = '''
+static const struct udevice_id test_ids[] = {
+ { .compatible = "nvidia,tegra114-dvc" },
+ { }
+};
+
+U_BOOT_DRIVER(%s) = {
+ .name = "testing",
+ .id = UCLASS_RAM,
+ .of_match = test_ids,
+};
+''' % name
+ scan = src_scan.Scanner(None, None, phase)
+ scan._parse_driver('file1.c', driver1)
+ self.assertIn(name, scan._drivers)
+ drv1 = scan._drivers[name]
+
+ prop = FakeProp()
+ prop.name = 'compatible'
+ prop.value = 'nvidia,tegra114-i2c'
+ node = FakeNode()
+ node.name = 'testing'
+ node.props = {'compatible': prop}
+
+ # get_normalized_compat_name() uses this to check for root node
+ node.parent = FakeNode()
+
+ return scan, drv1, driver2, node
+
+ def test_dup_drivers(self):
+ """Test handling of duplicate drivers"""
+ name = 'nvidia_tegra114_i2c'
+ scan, drv1, driver2, node = self.setup_dup_drivers(name)
+ self.assertEqual('', drv1.phase)
+
+ # The driver should not have a duplicate yet
+ self.assertEqual([], drv1.dups)
+
+ scan._parse_driver('file2.c', driver2)
+
+ # The first driver should now be a duplicate of the second
+ drv2 = scan._drivers[name]
+ self.assertEqual('', drv2.phase)
+ self.assertEqual(1, len(drv2.dups))
+ self.assertEqual([drv1], drv2.dups)
+
+ # There is no way to distinguish them, so we should expect a warning
+ self.assertTrue(drv2.warn_dups)
+
+ # We should see a warning
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.mark_used([node])
+ self.assertEqual(
+ "Warning: Duplicate driver name 'nvidia_tegra114_i2c' (orig=file2.c, dups=file1.c)",
+ stdout.getvalue().strip())
+
+ def test_dup_drivers_phase(self):
+ """Test handling of duplicate drivers but with different phases"""
+ name = 'nvidia_tegra114_i2c'
+ scan, drv1, driver2, node = self.setup_dup_drivers(name, 'spl')
+ scan._parse_driver('file2.c', driver2)
+ self.assertEqual('spl', drv1.phase)
+
+ # The second driver should now be a duplicate of the second
+ self.assertEqual(1, len(drv1.dups))
+ drv2 = drv1.dups[0]
+
+ # The phase is different, so we should not warn of dups
+ self.assertFalse(drv1.warn_dups)
+
+ # We should not see a warning
+ with test_util.capture_sys_output() as (stdout, _):
+ scan.mark_used([node])
+ self.assertEqual('', stdout.getvalue().strip())
+
+ def test_sequence(self):
+ """Test assignment of sequence numnbers"""
+ scan = src_scan.Scanner(None, None, '')
+ node = FakeNode()
+ uc = src_scan.UclassDriver('UCLASS_I2C')
+ node.uclass = uc
+ node.driver = True
+ node.seq = -1
+ node.path = 'mypath'
+ uc.alias_num_to_node[2] = node
+
+ # This should assign 3 (after the 2 that exists)
+ seq = scan.assign_seq(node)
+ self.assertEqual(3, seq)
+ self.assertEqual({'mypath': 3}, uc.alias_path_to_num)
+ self.assertEqual({2: node, 3: node}, uc.alias_num_to_node)