diff options
-rw-r--r-- | tools/dtoc/dtb_platdata.py | 96 | ||||
-rw-r--r-- | tools/dtoc/dtoc_test_driver_alias.dts | 20 | ||||
-rwxr-xr-x | tools/dtoc/test_dtoc.py | 33 |
3 files changed, 145 insertions, 4 deletions
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index bc0de426a9..1662d7ddb1 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -13,6 +13,8 @@ static data. import collections import copy +import os +import re import sys from dtoc import fdt @@ -143,6 +145,11 @@ class DtbPlatdata(object): _aliases: Dict that hold aliases for compatible strings key: First compatible string declared in a node value: List of additional compatible strings declared in a node + _drivers: List of valid driver names found in drivers/ + _driver_aliases: Dict that holds aliases for driver names + key: Driver alias declared with + U_BOOT_DRIVER_ALIAS(driver_alias, driver_name) + value: Driver name declared with U_BOOT_DRIVER(driver_name) """ def __init__(self, dtb_fname, include_disabled): self._fdt = None @@ -152,6 +159,38 @@ class DtbPlatdata(object): self._outfile = None self._lines = [] self._aliases = {} + self._drivers = [] + self._driver_aliases = {} + + def get_normalized_compat_name(self, node): + """Get a node's normalized compat name + + Returns a valid driver name by retrieving node's first compatible + string as a C identifier and performing a check against _drivers + and a lookup in driver_aliases printing a warning in case of failure. + + Args: + node: Node object to check + Return: + Tuple: + Driver name associated with the first compatible string + List of C identifiers for all the other compatible strings + (possibly empty) + In case of no match found, the return will be the same as + get_compat_name() + """ + compat_c, aliases_c = get_compat_name(node) + if compat_c not in self._drivers: + compat_c_old = compat_c + compat_c = self._driver_aliases.get(compat_c) + if not compat_c: + print('WARNING: the driver %s was not found in the driver list' + % (compat_c_old)) + compat_c = compat_c_old + else: + aliases_c = [compat_c_old] + aliases_c + + return compat_c, aliases_c def setup_output(self, fname): """Set up the output destination @@ -246,6 +285,54 @@ class DtbPlatdata(object): return PhandleInfo(max_args, args) return None + def scan_driver(self, fn): + """Scan a driver file to build a list of driver names and aliases + + This procedure will populate self._drivers and self._driver_aliases + + Args + fn: Driver filename to scan + """ + with open(fn, encoding='utf-8') as fd: + try: + buff = fd.read() + except UnicodeDecodeError: + # This seems to happen on older Python versions + print("Skipping file '%s' due to unicode error" % fn) + return + + # The following re will search for driver names declared as + # U_BOOT_DRIVER(driver_name) + drivers = re.findall('U_BOOT_DRIVER\((.*)\)', buff) + + for driver in drivers: + self._drivers.append(driver) + + # The following re will search for driver aliases declared as + # U_BOOT_DRIVER_ALIAS(alias, driver_name) + driver_aliases = re.findall('U_BOOT_DRIVER_ALIAS\(\s*(\w+)\s*,\s*(\w+)\s*\)', + buff) + + for alias in driver_aliases: # pragma: no cover + if len(alias) != 2: + continue + self._driver_aliases[alias[1]] = alias[0] + + def scan_drivers(self): + """Scan the driver folders to build a list of driver names and aliases + + This procedure will populate self._drivers and self._driver_aliases + + """ + basedir = sys.argv[0].replace('tools/dtoc/dtoc', '') + if basedir == '': + basedir = './' + for (dirpath, dirnames, filenames) in os.walk(basedir): + for fn in filenames: + if not fn.endswith('.c'): + continue + self.scan_driver(dirpath + '/' + fn) + def scan_dtb(self): """Scan the device tree to obtain a tree of nodes and properties @@ -356,7 +443,7 @@ class DtbPlatdata(object): """ structs = {} for node in self._valid_nodes: - node_name, _ = get_compat_name(node) + node_name, _ = self.get_normalized_compat_name(node) fields = {} # Get a list of all the valid properties in this node. @@ -380,14 +467,14 @@ class DtbPlatdata(object): upto = 0 for node in self._valid_nodes: - node_name, _ = get_compat_name(node) + node_name, _ = self.get_normalized_compat_name(node) struct = structs[node_name] for name, prop in node.props.items(): if name not in PROP_IGNORE_LIST and name[0] != '#': prop.Widen(struct[name]) upto += 1 - struct_name, aliases = get_compat_name(node) + struct_name, aliases = self.get_normalized_compat_name(node) for alias in aliases: self._aliases[alias] = struct_name @@ -464,7 +551,7 @@ class DtbPlatdata(object): Args: node: node to output """ - struct_name, _ = get_compat_name(node) + struct_name, _ = self.get_normalized_compat_name(node) var_name = conv_name_to_c(node.name) self.buf('static const struct %s%s %s%s = {\n' % (STRUCT_PREFIX, struct_name, VAL_PREFIX, var_name)) @@ -565,6 +652,7 @@ def run_steps(args, dtb_file, include_disabled, output): raise ValueError('Please specify a command: struct, platdata') plat = DtbPlatdata(dtb_file, include_disabled) + plat.scan_drivers() plat.scan_dtb() plat.scan_tree() plat.scan_reg_sizes() diff --git a/tools/dtoc/dtoc_test_driver_alias.dts b/tools/dtoc/dtoc_test_driver_alias.dts new file mode 100644 index 0000000000..da7973b2e5 --- /dev/null +++ b/tools/dtoc/dtoc_test_driver_alias.dts @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test device tree file for dtoc + * + * Copyright 2020 Collabora Ltd. + */ + +/dts-v1/; + +/ { + gpio_a: gpios@0 { + u-boot,dm-pre-reloc; + gpio-controller; + compatible = "sandbox_gpio_alias"; + #gpio-cells = <1>; + gpio-bank-name = "a"; + sandbox,gpio-count = <20>; + }; + +}; diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index 8498e8303c..91fc9d77f3 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -268,6 +268,39 @@ U_BOOT_DEVICE(pmic_at_9) = { ''', data) + def test_driver_alias(self): + """Test output from a device tree file with a driver alias""" + dtb_file = get_dtb_file('dtoc_test_driver_alias.dts') + output = tools.GetOutputFilename('output') + dtb_platdata.run_steps(['struct'], dtb_file, False, output) + with open(output) as infile: + data = infile.read() + self._CheckStrings(HEADER + ''' +struct dtd_sandbox_gpio { +\tconst char *\tgpio_bank_name; +\tbool\t\tgpio_controller; +\tfdt32_t\t\tsandbox_gpio_count; +}; +#define dtd_sandbox_gpio_alias dtd_sandbox_gpio +''', data) + + dtb_platdata.run_steps(['platdata'], dtb_file, False, output) + with open(output) as infile: + data = infile.read() + self._CheckStrings(C_HEADER + ''' +static const struct dtd_sandbox_gpio dtv_gpios_at_0 = { +\t.gpio_bank_name\t\t= "a", +\t.gpio_controller\t= true, +\t.sandbox_gpio_count\t= 0x14, +}; +U_BOOT_DEVICE(gpios_at_0) = { +\t.name\t\t= "sandbox_gpio", +\t.platdata\t= &dtv_gpios_at_0, +\t.platdata_size\t= sizeof(dtv_gpios_at_0), +}; + +''', data) + def test_phandle(self): """Test output from a node containing a phandle reference""" dtb_file = get_dtb_file('dtoc_test_phandle.dts') |