aboutsummaryrefslogtreecommitdiff
path: root/tools/dtoc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/dtoc')
-rw-r--r--tools/dtoc/dtb_platdata.py620
-rw-r--r--tools/dtoc/dtoc_test_scan_drivers.cxx1
-rwxr-xr-xtools/dtoc/main.py9
-rw-r--r--tools/dtoc/src_scan.py597
-rw-r--r--tools/dtoc/test/dtoc_test.dts (renamed from tools/dtoc/dtoc_test.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_add_prop.dts (renamed from tools/dtoc/dtoc_test_add_prop.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_addr32.dts (renamed from tools/dtoc/dtoc_test_addr32.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_addr32_64.dts (renamed from tools/dtoc/dtoc_test_addr32_64.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_addr64.dts (renamed from tools/dtoc/dtoc_test_addr64.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_addr64_32.dts (renamed from tools/dtoc/dtoc_test_addr64_32.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_alias_bad.dts58
-rw-r--r--tools/dtoc/test/dtoc_test_alias_bad_path.dts58
-rw-r--r--tools/dtoc/test/dtoc_test_alias_bad_uc.dts58
-rw-r--r--tools/dtoc/test/dtoc_test_aliases.dts (renamed from tools/dtoc/dtoc_test_aliases.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_bad_reg.dts (renamed from tools/dtoc/dtoc_test_bad_reg.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_bad_reg2.dts (renamed from tools/dtoc/dtoc_test_bad_reg2.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_driver_alias.dts (renamed from tools/dtoc/dtoc_test_driver_alias.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_empty.dts (renamed from tools/dtoc/dtoc_test_empty.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_inst.dts58
-rw-r--r--tools/dtoc/test/dtoc_test_invalid_driver.dts (renamed from tools/dtoc/dtoc_test_invalid_driver.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle.dts (renamed from tools/dtoc/dtoc_test_phandle.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_bad.dts (renamed from tools/dtoc/dtoc_test_phandle_bad.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_bad2.dts (renamed from tools/dtoc/dtoc_test_phandle_bad2.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts (renamed from tools/dtoc/dtoc_test_phandle_cd_gpios.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_reorder.dts (renamed from tools/dtoc/dtoc_test_phandle_reorder.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_phandle_single.dts (renamed from tools/dtoc/dtoc_test_phandle_single.dts)0
-rw-r--r--tools/dtoc/test/dtoc_test_scan_drivers.cxx5
-rw-r--r--tools/dtoc/test/dtoc_test_simple.dts (renamed from tools/dtoc/dtoc_test_simple.dts)4
-rwxr-xr-xtools/dtoc/test_dtoc.py1023
-rwxr-xr-xtools/dtoc/test_fdt.py31
-rw-r--r--tools/dtoc/test_src_scan.py397
31 files changed, 2753 insertions, 166 deletions
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index b7abaed..b5c449e 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -52,6 +52,20 @@ TYPE_NAMES = {
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)
@@ -136,8 +150,10 @@ class DtbPlatdata():
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: A list of Node object with compatible strings. The list
- is ordered by conv_name_to_c(node.name)
+ _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
@@ -149,18 +165,25 @@ class DtbPlatdata():
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):
+ 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
@@ -223,6 +246,7 @@ class DtbPlatdata():
"""
if self._outfile != sys.stdout:
self._outfile.close()
+ self._outfile = None
def out(self, line):
"""Output a string to the output file
@@ -281,7 +305,11 @@ class DtbPlatdata():
ValueError: if the phandle cannot be parsed or the required property
is not present
"""
- if prop.name in ['clocks', 'cd-gpios']:
+ 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
@@ -301,14 +329,10 @@ class DtbPlatdata():
if not target:
raise ValueError("Cannot parse '%s' in node '%s'" %
(prop.name, node_name))
- cells = None
- for prop_name in ['#clock-cells', '#gpio-cells']:
- cells = target.props.get(prop_name)
- if cells:
- break
+ cells = target.props.get(cells_prop)
if not cells:
raise ValueError("Node '%s' has no cells property" %
- (target.name))
+ target.name)
num_args = fdt_util.fdt32_to_cpu(cells.value)
max_args = max(max_args, num_args)
args.append(num_args)
@@ -324,38 +348,84 @@ class DtbPlatdata():
"""
self._fdt = fdt.FdtScan(self._dtb_fname)
- def scan_node(self, root, valid_nodes):
+ def scan_node(self, node, valid_nodes):
"""Scan a node and subnodes to build a tree of node and phandle info
- This adds each node to self._valid_nodes.
+ This adds each subnode to self._valid_nodes if it is enabled and has a
+ compatible string.
Args:
- root (Node): Root node for scan
+ node (Node): Node for scan for subnodes
valid_nodes (list of Node): List of Node objects to add to
"""
- for node in root.subnodes:
- if 'compatible' in node.props:
- status = node.props.get('status')
+ 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(node)
+ valid_nodes.append(subnode)
# recurse to handle any subnodes
- self.scan_node(node, valid_nodes)
+ self.scan_node(subnode, valid_nodes)
- def scan_tree(self):
+ def scan_tree(self, add_root):
"""Scan the device tree for useful information
This fills in the following properties:
- _valid_nodes: A list of nodes we wish to consider include in the
- platform data
+ _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 = []
- self.scan_node(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):
@@ -434,7 +504,6 @@ class DtbPlatdata():
"""
structs = self._struct_data
for node in self._valid_nodes:
- node_name, _ = self._scan.get_normalized_compat_name(node)
fields = {}
# Get a list of all the valid properties in this node.
@@ -442,9 +511,9 @@ class DtbPlatdata():
if name not in PROP_IGNORE_LIST and name[0] != '#':
fields[name] = copy.deepcopy(prop)
- # If we've seen this node_name before, update the existing struct.
- if node_name in structs:
- struct = structs[node_name]
+ # 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:
@@ -454,11 +523,10 @@ class DtbPlatdata():
# Otherwise store this as a new struct.
else:
- structs[node_name] = fields
+ structs[node.struct_name] = fields
for node in self._valid_nodes:
- node_name, _ = self._scan.get_normalized_compat_name(node)
- struct = structs[node_name]
+ 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])
@@ -562,28 +630,145 @@ class DtbPlatdata():
self.buf(', '.join(vals[i:i + 8]))
self.buf('}')
- def _declare_device(self, var_name, struct_name, node_parent):
+ def _declare_device(self, node):
"""Add a device declaration to the output
This declares a U_BOOT_DRVINFO() for the device being processed
Args:
- var_name (str): C name for the node
- struct_name (str): Name for the dt struct associated with the node
- node_parent (Node): Parent of the node (or None if none)
+ node: Node to process
"""
- self.buf('U_BOOT_DRVINFO(%s) = {\n' % var_name)
- self.buf('\t.name\t\t= "%s",\n' % struct_name)
- self.buf('\t.plat\t= &%s%s,\n' % (VAL_PREFIX, var_name))
- self.buf('\t.plat_size\t= sizeof(%s%s),\n' % (VAL_PREFIX, var_name))
+ 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
+ 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 _output_prop(self, node, prop):
+ 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:
@@ -593,7 +778,7 @@ class DtbPlatdata():
if prop.name in PROP_IGNORE_LIST or prop.name[0] == '#':
return
member_name = conv_name_to_c(prop.name)
- self.buf('\t%s= ' % tab_to(3, '.' + member_name))
+ self.buf('%s%s= ' % ('\t' * tabs, tab_to(3, '.' + member_name)))
# Special handling for lists
if isinstance(prop.value, list):
@@ -602,35 +787,269 @@ class DtbPlatdata():
self.buf(get_value(prop.type, prop.value))
self.buf(',\n')
- def _output_values(self, var_name, struct_name, node):
+ def _output_values(self, node):
"""Output the definition of a device's struct values
Args:
- var_name (str): C name for the node
- struct_name (str): Name for the dt struct associated with the node
- node (Node): Node being output
+ node (Node): Node to output
"""
self.buf('static struct %s%s %s%s = {\n' %
- (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name))
+ (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 output_node(self, node):
+ 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):
+ if not self.check_instantiate(True):
+ return
+ 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
"""
- struct_name, _ = self._scan.get_normalized_compat_name(node)
- var_name = conv_name_to_c(node.name)
- self.buf('/* Node %s index %d */\n' % (node.path, node.idx))
+ 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')
- self._output_values(var_name, struct_name, node)
- self._declare_device(var_name, struct_name, node.parent)
+ if not node.driver.plat:
+ self._output_values(node)
+ self._declare_device_inst(node, parent_driver)
self.out(''.join(self.get_buf()))
+ def check_instantiate(self, require):
+ """Check if self._instantiate is set to the required value
+
+ If not, this outputs a message into the current file
+
+ Args:
+ require: True to require --instantiate, False to require that it not
+ be enabled
+ """
+ if require != self._instantiate:
+ self.out(
+ '/* This file is not used: --instantiate was %senabled */\n' %
+ ('not ' if require else ''))
+ return False
+ return True
+
def generate_plat(self):
"""Generate device defintions for the platform data
@@ -641,6 +1060,8 @@ class DtbPlatdata():
See the documentation in doc/driver-model/of-plat.rst for more
information.
"""
+ if not self.check_instantiate(False):
+ return
self.out('/* Allow use of U_BOOT_DRVINFO() in this file */\n')
self.out('#define DT_PLAT_C\n')
self.out('\n')
@@ -649,8 +1070,57 @@ class DtbPlatdata():
self.out('#include <dt-structs.h>\n')
self.out('\n')
- for node in self._valid_nodes:
- self.output_node(node)
+ 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.
+ """
+ if not self.check_instantiate(True):
+ return
+ 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()))
@@ -659,6 +1129,9 @@ class DtbPlatdata():
# key: Command used to generate this file
# value: OutputFile for this command
OUTPUT_FILES = {
+ '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,
@@ -666,11 +1139,18 @@ OUTPUT_FILES = {
'platdata':
OutputFile(Ftype.SOURCE, 'dt-plat.c', DtbPlatdata.generate_plat,
'Declares the U_BOOT_DRIVER() records and platform data'),
+ '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,
- warning_disabled=False, drivers_additional=None, basedir=None):
+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:
@@ -681,12 +1161,22 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
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
"""
@@ -695,15 +1185,24 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
if output and output_dirs and any(output_dirs):
raise ValueError('Must specify either output or output_dirs, not both')
- scan = src_scan.Scanner(basedir, warning_disabled, drivers_additional)
- plat = DtbPlatdata(scan, dtb_file, include_disabled)
- scan.scan_drivers()
+ if not scan:
+ scan = src_scan.Scanner(basedir, warning_disabled, 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()
+ 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()
cmds = args[0].split(',')
if 'all' in cmds:
@@ -718,3 +1217,4 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs,
plat.out_header(outfile)
outfile.method(plat)
plat.finish_output()
+ return plat
diff --git a/tools/dtoc/dtoc_test_scan_drivers.cxx b/tools/dtoc/dtoc_test_scan_drivers.cxx
deleted file mode 100644
index f448767..0000000
--- a/tools/dtoc/dtoc_test_scan_drivers.cxx
+++ /dev/null
@@ -1 +0,0 @@
-DM_DRIVER_ALIAS(sandbox_gpio, sandbox_gpio_alias2)
diff --git a/tools/dtoc/main.py b/tools/dtoc/main.py
index b0ad0f3..93706de 100755
--- a/tools/dtoc/main.py
+++ b/tools/dtoc/main.py
@@ -53,6 +53,8 @@ def run_tests(processes, args):
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=[],
@@ -79,10 +81,14 @@ 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',
@@ -102,4 +108,5 @@ elif options.test_coverage:
else:
dtb_platdata.run_steps(args, options.dtb_file, options.include_disabled,
options.output,
- [options.c_output_dir, options.h_output_dir])
+ [options.c_output_dir, options.h_output_dir],
+ options.phase, instantiate=options.instantiate)
diff --git a/tools/dtoc/src_scan.py b/tools/dtoc/src_scan.py
index f63c9fc..114212c 100644
--- a/tools/dtoc/src_scan.py
+++ b/tools/dtoc/src_scan.py
@@ -33,6 +33,8 @@ def conv_name_to_c(name):
new = new.replace('-', '_')
new = new.replace(',', '_')
new = new.replace('.', '_')
+ if new == '/':
+ return 'root'
return new
def get_compat_name(node):
@@ -54,15 +56,123 @@ class Driver:
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
+ return (self.name == other.name and
+ self.uclass_id == other.uclass_id and
+ self.priv == other.priv)
def __repr__(self):
- return "Driver(name='%s')" % self.name
+ 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:
@@ -81,8 +191,22 @@ class Scanner:
_warning_disabled: true to disable warnings about driver names not found
_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, warning_disabled, drivers_additional):
+ def __init__(self, basedir, warning_disabled, drivers_additional, phase=''):
"""Set up a new Scanner
"""
if not basedir:
@@ -94,6 +218,22 @@ class Scanner:
self._driver_aliases = {}
self._drivers_additional = drivers_additional or []
self._warning_disabled = warning_disabled
+ 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
@@ -112,7 +252,10 @@ class Scanner:
In case of no match found, the return will be the same as
get_compat_name()
"""
- compat_list_c = get_compat_name(node)
+ 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():
@@ -131,10 +274,319 @@ class Scanner:
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 scan_driver(self, fname):
"""Scan a driver file to build a list of driver names and aliases
- This procedure will populate self._drivers and self._driver_aliases
+ 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
@@ -147,23 +599,35 @@ class Scanner:
print("Skipping file '%s' due to unicode error" % fname)
return
- # The following re will search for driver names declared as
- # U_BOOT_DRIVER(driver_name)
- drivers = re.findall(r'U_BOOT_DRIVER\((.*)\)', buff)
+ # 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)
- for driver in drivers:
- self._drivers[driver] = Driver(driver)
+ def scan_header(self, fname):
+ """Scan a header file to build a list of struct definitions
- # The following re will search for driver aliases declared as
- # DM_DRIVER_ALIAS(alias, driver_name)
- driver_aliases = re.findall(
- r'DM_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)',
- buff)
+ It updates the following members:
+ _structs - updated with new Struct records for each struct found
+ in the file
- for alias in driver_aliases: # pragma: no cover
- if len(alias) != 2:
- continue
- self._driver_aliases[alias[1]] = alias[0]
+ 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
@@ -171,11 +635,17 @@ class Scanner:
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:
- if not fname.endswith('.c'):
- continue
- self.scan_driver(dirpath + '/' + fname)
-
+ 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
@@ -183,3 +653,84 @@ class Scanner:
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/tools/dtoc/dtoc_test.dts b/tools/dtoc/test/dtoc_test.dts
index b225948..b225948 100644
--- a/tools/dtoc/dtoc_test.dts
+++ b/tools/dtoc/test/dtoc_test.dts
diff --git a/tools/dtoc/dtoc_test_add_prop.dts b/tools/dtoc/test/dtoc_test_add_prop.dts
index fa296e5..fa296e5 100644
--- a/tools/dtoc/dtoc_test_add_prop.dts
+++ b/tools/dtoc/test/dtoc_test_add_prop.dts
diff --git a/tools/dtoc/dtoc_test_addr32.dts b/tools/dtoc/test/dtoc_test_addr32.dts
index 2390454..2390454 100644
--- a/tools/dtoc/dtoc_test_addr32.dts
+++ b/tools/dtoc/test/dtoc_test_addr32.dts
diff --git a/tools/dtoc/dtoc_test_addr32_64.dts b/tools/dtoc/test/dtoc_test_addr32_64.dts
index 7599d5b..7599d5b 100644
--- a/tools/dtoc/dtoc_test_addr32_64.dts
+++ b/tools/dtoc/test/dtoc_test_addr32_64.dts
diff --git a/tools/dtoc/dtoc_test_addr64.dts b/tools/dtoc/test/dtoc_test_addr64.dts
index 263d251..263d251 100644
--- a/tools/dtoc/dtoc_test_addr64.dts
+++ b/tools/dtoc/test/dtoc_test_addr64.dts
diff --git a/tools/dtoc/dtoc_test_addr64_32.dts b/tools/dtoc/test/dtoc_test_addr64_32.dts
index 85e4f5f..85e4f5f 100644
--- a/tools/dtoc/dtoc_test_addr64_32.dts
+++ b/tools/dtoc/test/dtoc_test_addr64_32.dts
diff --git a/tools/dtoc/test/dtoc_test_alias_bad.dts b/tools/dtoc/test/dtoc_test_alias_bad.dts
new file mode 100644
index 0000000..d4f502a
--- /dev/null
+++ b/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/tools/dtoc/test/dtoc_test_alias_bad_path.dts b/tools/dtoc/test/dtoc_test_alias_bad_path.dts
new file mode 100644
index 0000000..0beca4f
--- /dev/null
+++ b/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/tools/dtoc/test/dtoc_test_alias_bad_uc.dts b/tools/dtoc/test/dtoc_test_alias_bad_uc.dts
new file mode 100644
index 0000000..ae64f5b
--- /dev/null
+++ b/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/tools/dtoc/dtoc_test_aliases.dts b/tools/dtoc/test/dtoc_test_aliases.dts
index ae33716..ae33716 100644
--- a/tools/dtoc/dtoc_test_aliases.dts
+++ b/tools/dtoc/test/dtoc_test_aliases.dts
diff --git a/tools/dtoc/dtoc_test_bad_reg.dts b/tools/dtoc/test/dtoc_test_bad_reg.dts
index 1312acb..1312acb 100644
--- a/tools/dtoc/dtoc_test_bad_reg.dts
+++ b/tools/dtoc/test/dtoc_test_bad_reg.dts
diff --git a/tools/dtoc/dtoc_test_bad_reg2.dts b/tools/dtoc/test/dtoc_test_bad_reg2.dts
index 3e9efa4..3e9efa4 100644
--- a/tools/dtoc/dtoc_test_bad_reg2.dts
+++ b/tools/dtoc/test/dtoc_test_bad_reg2.dts
diff --git a/tools/dtoc/dtoc_test_driver_alias.dts b/tools/dtoc/test/dtoc_test_driver_alias.dts
index da7973b..da7973b 100644
--- a/tools/dtoc/dtoc_test_driver_alias.dts
+++ b/tools/dtoc/test/dtoc_test_driver_alias.dts
diff --git a/tools/dtoc/dtoc_test_empty.dts b/tools/dtoc/test/dtoc_test_empty.dts
index b225948..b225948 100644
--- a/tools/dtoc/dtoc_test_empty.dts
+++ b/tools/dtoc/test/dtoc_test_empty.dts
diff --git a/tools/dtoc/test/dtoc_test_inst.dts b/tools/dtoc/test/dtoc_test_inst.dts
new file mode 100644
index 0000000..b8177fc
--- /dev/null
+++ b/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/tools/dtoc/dtoc_test_invalid_driver.dts b/tools/dtoc/test/dtoc_test_invalid_driver.dts
index 914ac3e..914ac3e 100644
--- a/tools/dtoc/dtoc_test_invalid_driver.dts
+++ b/tools/dtoc/test/dtoc_test_invalid_driver.dts
diff --git a/tools/dtoc/dtoc_test_phandle.dts b/tools/dtoc/test/dtoc_test_phandle.dts
index a71acff..a71acff 100644
--- a/tools/dtoc/dtoc_test_phandle.dts
+++ b/tools/dtoc/test/dtoc_test_phandle.dts
diff --git a/tools/dtoc/dtoc_test_phandle_bad.dts b/tools/dtoc/test/dtoc_test_phandle_bad.dts
index a3ddc59..a3ddc59 100644
--- a/tools/dtoc/dtoc_test_phandle_bad.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_bad.dts
diff --git a/tools/dtoc/dtoc_test_phandle_bad2.dts b/tools/dtoc/test/dtoc_test_phandle_bad2.dts
index fe25f56..fe25f56 100644
--- a/tools/dtoc/dtoc_test_phandle_bad2.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_bad2.dts
diff --git a/tools/dtoc/dtoc_test_phandle_cd_gpios.dts b/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts
index 241743e..241743e 100644
--- a/tools/dtoc/dtoc_test_phandle_cd_gpios.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_cd_gpios.dts
diff --git a/tools/dtoc/dtoc_test_phandle_reorder.dts b/tools/dtoc/test/dtoc_test_phandle_reorder.dts
index aa71d56..aa71d56 100644
--- a/tools/dtoc/dtoc_test_phandle_reorder.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_reorder.dts
diff --git a/tools/dtoc/dtoc_test_phandle_single.dts b/tools/dtoc/test/dtoc_test_phandle_single.dts
index aacd0b1..aacd0b1 100644
--- a/tools/dtoc/dtoc_test_phandle_single.dts
+++ b/tools/dtoc/test/dtoc_test_phandle_single.dts
diff --git a/tools/dtoc/test/dtoc_test_scan_drivers.cxx b/tools/dtoc/test/dtoc_test_scan_drivers.cxx
new file mode 100644
index 0000000..f370b89
--- /dev/null
+++ b/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/tools/dtoc/dtoc_test_simple.dts b/tools/dtoc/test/dtoc_test_simple.dts
index 1c87b89..d8ab861 100644
--- a/tools/dtoc/dtoc_test_simple.dts
+++ b/tools/dtoc/test/dtoc_test_simple.dts
@@ -45,12 +45,12 @@
};
i2c@0 {
- compatible = "sandbox,i2c-test";
+ compatible = "sandbox,i2c";
u-boot,dm-pre-reloc;
#address-cells = <1>;
#size-cells = <0>;
pmic@9 {
- compatible = "sandbox,pmic-test";
+ compatible = "sandbox,pmic";
u-boot,dm-pre-reloc;
reg = <9>;
low-power;
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index d961d67..1912a87 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -10,16 +10,19 @@ 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
@@ -38,13 +41,23 @@ HEADER = '''/*
#include <stdbool.h>
#include <linux/libfdt.h>'''
-C_HEADER = '''/*
+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
@@ -53,6 +66,21 @@ C_HEADER = '''/*
#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.
+ */
+'''
+
+UCLASS_HEADER = UCLASS_HEADER_COMMON + '''
+/* This file is not used: --instantiate was not enabled */
+'''
+
+# 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
@@ -67,10 +95,23 @@ def get_dtb_file(dts_fname, capture_stderr=False):
Returns:
str: Filename of compiled file in output directory
"""
- return fdt_util.EnsureCompiled(os.path.join(OUR_PATH, dts_fname),
+ 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, True, 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
@@ -112,15 +153,22 @@ class TestDtoc(unittest.TestCase):
self.assertEqual(expected, actual)
@staticmethod
- def run_test(args, dtb_file, output):
+ 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
"""
- dtb_platdata.run_steps(args, dtb_file, False, output, [], True)
+ # 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"""
@@ -175,7 +223,10 @@ class TestDtoc(unittest.TestCase):
"""Test output from a device tree file with no nodes"""
dtb_file = get_dtb_file('dtoc_test_empty.dts')
output = tools.GetOutputFilename('output')
- self.run_test(['struct'], dtb_file, 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)
@@ -185,10 +236,62 @@ class TestDtoc(unittest.TestCase):
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_test {
+struct dtd_sandbox_i2c {
};
-struct dtd_sandbox_pmic_test {
+struct dtd_sandbox_pmic {
\tbool\t\tlow_power;
\tfdt64_t\t\treg[2];
};
@@ -205,31 +308,52 @@ struct dtd_sandbox_spl_test {
\tconst char *\tstringval;
};
'''
-
platdata_text = C_HEADER + '''
-/* Node /i2c@0 index 0 */
-static struct dtd_sandbox_i2c_test dtv_i2c_at_0 = {
+/*
+ * 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_test",
-\t.plat\t= &dtv_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 */
-static struct dtd_sandbox_pmic_test dtv_pmic_at_9 = {
+/*
+ * 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, 0x0},
};
U_BOOT_DRVINFO(pmic_at_9) = {
-\t.name\t\t= "sandbox_pmic_test",
-\t.plat\t= &dtv_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 */
+/*
+ * 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},
@@ -244,12 +368,15 @@ static struct dtd_sandbox_spl_test dtv_spl_test = {
};
U_BOOT_DRVINFO(spl_test) = {
\t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_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 */
+/*
+ * 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},
@@ -263,12 +390,15 @@ static struct dtd_sandbox_spl_test dtv_spl_test2 = {
};
U_BOOT_DRVINFO(spl_test2) = {
\t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test2,
+\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 */
+/*
+ * 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},
@@ -276,12 +406,406 @@ static struct dtd_sandbox_spl_test dtv_spl_test3 = {
};
U_BOOT_DRVINFO(spl_test3) = {
\t.name\t\t= "sandbox_spl_test",
-\t.plat\t= &dtv_spl_test3,
+\t.plat\t\t= &dtv_spl_test3,
\t.plat_size\t= sizeof(dtv_spl_test3),
\t.parent_idx\t= -1,
};
'''
+ uclass_text = UCLASS_HEADER
+ 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 = '''/*
+ * DO NOT MODIFY
+ *
+ * Declares the DM_DEVICE_INST() records.
+ * This was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+/* This file is not used: --instantiate was not enabled */
+'''
+ 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, 0x0},
+\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"""
@@ -299,10 +823,18 @@ U_BOOT_DRVINFO(spl_test3) = {
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.platdata_text + self.struct_text, data)
+ self._check_strings(
+ self.decl_text + self.device_text + self.platdata_text +
+ self.struct_text + self.uclass_text, data)
def test_driver_alias(self):
"""Test output from a device tree file with a driver alias"""
@@ -323,7 +855,19 @@ struct dtd_sandbox_gpio {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
-/* Node /gpios@0 index 0 */
+/*
+ * 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,
@@ -331,7 +875,7 @@ static struct dtd_sandbox_gpio dtv_gpios_at_0 = {
};
U_BOOT_DRVINFO(gpios_at_0) = {
\t.name\t\t= "sandbox_gpio",
-\t.plat\t= &dtv_gpios_at_0,
+\t.plat\t\t= &dtv_gpios_at_0,
\t.plat_size\t= sizeof(dtv_gpios_at_0),
\t.parent_idx\t= -1,
};
@@ -343,7 +887,9 @@ U_BOOT_DRVINFO(gpios_at_0) = {
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, [])
+ 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 + '''
@@ -352,16 +898,27 @@ struct dtd_invalid {
''', data)
with test_util.capture_sys_output() as _:
- dtb_platdata.run_steps(['platdata'], dtb_file, False, output, [])
+ 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= &dtv_spl_test,
+\t.plat\t\t= &dtv_spl_test,
\t.plat_size\t= sizeof(dtv_spl_test),
\t.parent_idx\t= -1,
};
@@ -388,13 +945,26 @@ struct dtd_target {
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= &dtv_phandle2_target,
+\t.plat\t\t= &dtv_phandle2_target,
\t.plat_size\t= sizeof(dtv_phandle2_target),
\t.parent_idx\t= -1,
};
@@ -405,7 +975,7 @@ static struct dtd_target dtv_phandle3_target = {
};
U_BOOT_DRVINFO(phandle3_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle3_target,
+\t.plat\t\t= &dtv_phandle3_target,
\t.plat_size\t= sizeof(dtv_phandle3_target),
\t.parent_idx\t= -1,
};
@@ -420,7 +990,7 @@ static struct dtd_source dtv_phandle_source = {
};
U_BOOT_DRVINFO(phandle_source) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source,
+\t.plat\t\t= &dtv_phandle_source,
\t.plat_size\t= sizeof(dtv_phandle_source),
\t.parent_idx\t= -1,
};
@@ -432,7 +1002,7 @@ static struct dtd_source dtv_phandle_source2 = {
};
U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
@@ -443,7 +1013,7 @@ static struct dtd_target dtv_phandle_target = {
};
U_BOOT_DRVINFO(phandle_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
\t.plat_size\t= sizeof(dtv_phandle_target),
\t.parent_idx\t= -1,
};
@@ -474,6 +1044,16 @@ struct dtd_target {
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= {
@@ -481,7 +1061,7 @@ static struct dtd_source dtv_phandle_source2 = {
};
U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
@@ -491,7 +1071,7 @@ static struct dtd_target dtv_phandle_target = {
};
U_BOOT_DRVINFO(phandle_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
\t.plat_size\t= sizeof(dtv_phandle_target),
\t.parent_idx\t= -1,
};
@@ -502,17 +1082,32 @@ U_BOOT_DRVINFO(phandle_target) = {
"""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, [], True)
+ 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= &dtv_phandle2_target,
+\t.plat\t\t= &dtv_phandle2_target,
\t.plat_size\t= sizeof(dtv_phandle2_target),
\t.parent_idx\t= -1,
};
@@ -523,7 +1118,7 @@ static struct dtd_target dtv_phandle3_target = {
};
U_BOOT_DRVINFO(phandle3_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle3_target,
+\t.plat\t\t= &dtv_phandle3_target,
\t.plat_size\t= sizeof(dtv_phandle3_target),
\t.parent_idx\t= -1,
};
@@ -538,7 +1133,7 @@ static struct dtd_source dtv_phandle_source = {
};
U_BOOT_DRVINFO(phandle_source) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source,
+\t.plat\t\t= &dtv_phandle_source,
\t.plat_size\t= sizeof(dtv_phandle_source),
\t.parent_idx\t= -1,
};
@@ -550,7 +1145,7 @@ static struct dtd_source dtv_phandle_source2 = {
};
U_BOOT_DRVINFO(phandle_source2) = {
\t.name\t\t= "source",
-\t.plat\t= &dtv_phandle_source2,
+\t.plat\t\t= &dtv_phandle_source2,
\t.plat_size\t= sizeof(dtv_phandle_source2),
\t.parent_idx\t= -1,
};
@@ -561,7 +1156,7 @@ static struct dtd_target dtv_phandle_target = {
};
U_BOOT_DRVINFO(phandle_target) = {
\t.name\t\t= "target",
-\t.plat\t= &dtv_phandle_target,
+\t.plat\t\t= &dtv_phandle_target,
\t.plat_size\t= sizeof(dtv_phandle_target),
\t.parent_idx\t= -1,
};
@@ -611,13 +1206,24 @@ struct dtd_test3 {
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= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
\t.parent_idx\t= -1,
};
@@ -628,7 +1234,7 @@ static struct dtd_test2 dtv_test2 = {
};
U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
@@ -639,7 +1245,7 @@ static struct dtd_test3 dtv_test3 = {
};
U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
@@ -666,13 +1272,23 @@ struct dtd_test2 {
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= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
\t.parent_idx\t= -1,
};
@@ -683,7 +1299,7 @@ static struct dtd_test2 dtv_test2 = {
};
U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
@@ -713,13 +1329,24 @@ struct dtd_test3 {
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= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
\t.parent_idx\t= -1,
};
@@ -730,7 +1357,7 @@ static struct dtd_test2 dtv_test2 = {
};
U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
@@ -741,7 +1368,7 @@ static struct dtd_test3 dtv_test3 = {
};
U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
@@ -771,13 +1398,24 @@ struct dtd_test3 {
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= &dtv_test1,
+\t.plat\t\t= &dtv_test1,
\t.plat_size\t= sizeof(dtv_test1),
\t.parent_idx\t= -1,
};
@@ -788,7 +1426,7 @@ static struct dtd_test2 dtv_test2 = {
};
U_BOOT_DRVINFO(test2) = {
\t.name\t\t= "test2",
-\t.plat\t= &dtv_test2,
+\t.plat\t\t= &dtv_test2,
\t.plat_size\t= sizeof(dtv_test2),
\t.parent_idx\t= -1,
};
@@ -799,7 +1437,7 @@ static struct dtd_test3 dtv_test3 = {
};
U_BOOT_DRVINFO(test3) = {
\t.name\t\t= "test3",
-\t.plat\t= &dtv_test3,
+\t.plat\t\t= &dtv_test3,
\t.plat_size\t= sizeof(dtv_test3),
\t.parent_idx\t= -1,
};
@@ -845,24 +1483,40 @@ struct dtd_sandbox_spl_test {
with open(output) as infile:
data = infile.read()
self._check_strings(C_HEADER + '''
-/* Node /spl-test index 0 */
+/*
+ * 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= &dtv_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 */
+/*
+ * 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= &dtv_spl_test2,
+\t.plat\t\t= &dtv_spl_test2,
\t.plat_size\t= sizeof(dtv_spl_test2),
\t.parent_idx\t= -1,
};
@@ -882,7 +1536,9 @@ U_BOOT_DRVINFO(spl_test2) = {
output = tools.GetOutputFilename('output')
self.run_test(['all'], dtb_file, output)
data = tools.ReadFile(output, binary=False)
- self._check_strings(self.platdata_text + self.struct_text, data)
+ self._check_strings(
+ self.decl_text + self.device_text + self.platdata_text +
+ self.struct_text + self.uclass_text, data)
def test_no_command(self):
"""Test running dtoc without a command"""
@@ -897,13 +1553,16 @@ U_BOOT_DRVINFO(spl_test2) = {
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: platdata, struct)",
- str(exc.exception))
+ self.assertIn(
+ "Unknown command 'invalid-cmd': (use: decl, device, platdata, struct, uclass)",
+ 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'], True)
+ 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))
@@ -919,11 +1578,249 @@ U_BOOT_DRVINFO(spl_test2) = {
fnames = glob.glob(outdir + '/*')
self.assertEqual(2, len(fnames))
- dtb_platdata.run_steps(['all'], dtb_file, False, None, [outdir], True)
+ dtb_platdata.run_steps(
+ ['all'], dtb_file, False, None, [outdir], None, False,
+ warning_disabled=True, scan=copy_scan())
fnames = glob.glob(outdir + '/*')
- self.assertEqual(4, len(fnames))
+ self.assertEqual(7, 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-structs-gen.h', 'source.dts', 'dt-plat.c', '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(['platdata'], dtb_file, output, True)
+ with open(output) as infile:
+ data = infile.read()
+
+ self._check_strings(C_HEADER_PRE + '''
+/* This file is not used: --instantiate was enabled */
+''', 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())
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index e8fbbd5..1c3a8a2 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -48,6 +48,17 @@ def _GetPropertyValue(dtb, node, prop_name):
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
@@ -64,7 +75,7 @@ class TestFdt(unittest.TestCase):
tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
def testFdt(self):
"""Test that we can open an Fdt"""
@@ -141,7 +152,7 @@ class TestNode(unittest.TestCase):
tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
def testOffset(self):
@@ -203,7 +214,7 @@ class TestNode(unittest.TestCase):
def testLookupPhandle(self):
"""Test looking up a single phandle"""
- dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+ dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
node = dtb.GetNode('/phandle-source2')
prop = node.props['clocks']
target = dtb.GetNode('/phandle-target')
@@ -222,7 +233,7 @@ class TestProp(unittest.TestCase):
tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
self.fdt = self.dtb.GetFdtObj()
@@ -230,7 +241,7 @@ class TestProp(unittest.TestCase):
self.assertEqual(None, self.dtb.GetNode('missing'))
def testPhandle(self):
- dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+ 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)
@@ -488,7 +499,7 @@ class TestFdtUtil(unittest.TestCase):
tools.FinaliseOutputDir()
def setUp(self):
- self.dtb = fdt.FdtScan('tools/dtoc/dtoc_test_simple.dts')
+ self.dtb = fdt.FdtScan(find_dtb_file('dtoc_test_simple.dts'))
self.node = self.dtb.GetNode('/spl-test')
def testGetInt(self):
@@ -531,7 +542,7 @@ class TestFdtUtil(unittest.TestCase):
str(e.exception))
def testGetPhandleList(self):
- dtb = fdt.FdtScan('tools/dtoc/dtoc_test_phandle.dts')
+ 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')
@@ -551,7 +562,7 @@ class TestFdtUtil(unittest.TestCase):
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('tools/dtoc/dtoc_test_addr64.dts')
+ 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))
@@ -565,7 +576,7 @@ class TestFdtUtil(unittest.TestCase):
def testEnsureCompiled(self):
"""Test a degenerate case of this function (file already compiled)"""
- dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts')
+ dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'))
self.assertEqual(dtb, fdt_util.EnsureCompiled(dtb))
def testEnsureCompiledTmpdir(self):
@@ -574,7 +585,7 @@ class TestFdtUtil(unittest.TestCase):
old_outdir = tools.outdir
tools.outdir= None
tmpdir = tempfile.mkdtemp(prefix='test_fdt.')
- dtb = fdt_util.EnsureCompiled('tools/dtoc/dtoc_test_simple.dts',
+ dtb = fdt_util.EnsureCompiled(find_dtb_file('dtoc_test_simple.dts'),
tmpdir)
self.assertEqual(tmpdir, os.path.dirname(dtb))
shutil.rmtree(tmpdir)
diff --git a/tools/dtoc/test_src_scan.py b/tools/dtoc/test_src_scan.py
index 7d68653..0af86dc 100644
--- a/tools/dtoc/test_src_scan.py
+++ b/tools/dtoc/test_src_scan.py
@@ -7,6 +7,7 @@
This includes unit tests for scanning of the source code
"""
+import copy
import os
import shutil
import tempfile
@@ -17,6 +18,20 @@ 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
@@ -44,7 +59,8 @@ class TestSrcScan(unittest.TestCase):
def test_additional(self):
"""Test with additional drivers to scan"""
scan = src_scan.Scanner(
- None, True, [None, '', 'tools/dtoc/dtoc_test_scan_drivers.cxx'])
+ None, True,
+ [None, '', 'tools/dtoc/test/dtoc_test_scan_drivers.cxx'])
scan.scan_drivers()
self.assertIn('sandbox_gpio_alias2', scan._driver_aliases)
self.assertEqual('sandbox_gpio',
@@ -69,10 +85,22 @@ class TestSrcScan(unittest.TestCase):
def test_driver(self):
"""Test the Driver class"""
- drv1 = src_scan.Driver('fred')
- drv2 = src_scan.Driver('mary')
- drv3 = src_scan.Driver('fred')
- self.assertEqual("Driver(name='fred')", str(drv1))
+ 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)
@@ -91,7 +119,9 @@ class TestSrcScan(unittest.TestCase):
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
@@ -101,7 +131,362 @@ class TestSrcScan(unittest.TestCase):
self.assertEqual(2, len(mocked.mock_calls))
self.assertEqual(mock.call(fname_list[0]),
mocked.mock_calls[0])
- self.assertEqual(mock.call(fname_list[1]),
+ # .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, False, 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, False, 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(
+ '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, False, 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, False, 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, False, 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, False, 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, False, 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, False, 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, False, 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, False, 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, False, 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)