dtoc: Read aliases for uclasses

Scan the aliases in the device tree to establish the number of devices
within each uclass, and the sequence number of each.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2021-02-03 06:01:07 -07:00
parent 1d97269756
commit 059535291c
7 changed files with 345 additions and 3 deletions

View File

@ -647,6 +647,29 @@ class DtbPlatdata():
self._output_prop(node, node.props[pname])
self.buf('};\n')
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 process_nodes(self, need_drivers):
nodes_to_output = list(self._valid_nodes)
@ -757,6 +780,9 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
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
"""
@ -782,6 +808,7 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
plat.scan_phandles()
if do_process:
plat.process_nodes(False)
plat.read_aliases()
cmds = args[0].split(',')
if 'all' in cmds:
@ -796,3 +823,4 @@ def run_steps(args, dtb_file, include_disabled, output, output_dirs, phase,
plat.out_header(outfile)
outfile.method(plat)
plat.finish_output()
return plat

View File

@ -116,6 +116,13 @@ class UclassDriver:
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"
"""
def __init__(self, name):
self.name = name
@ -125,6 +132,8 @@ class UclassDriver:
self.per_dev_plat = ''
self.per_child_priv = ''
self.per_child_plat = ''
self.alias_num_to_node = {}
self.alias_path_to_num = {}
def __eq__(self, other):
return (self.name == other.name and
@ -622,7 +631,6 @@ class Scanner:
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
@ -652,3 +660,25 @@ class Scanner:
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

View File

@ -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";
};
};
};

View File

@ -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";
};
};
};

View File

@ -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";
};
};
};

View File

@ -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";
};
};
};

View File

@ -137,9 +137,12 @@ class TestDtoc(unittest.TestCase):
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, [], None,
warning_disabled=True, scan=copy_scan())
return dtb_platdata.run_steps(args, dtb_file, False, output, [], None,
warning_disabled=True, scan=copy_scan())
def test_name(self):
"""Test conversion of device tree names to C identifiers"""
@ -1040,3 +1043,52 @@ U_BOOT_DRVINFO(spl_test2) = {
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')
self.assertIn('UCLASS_TEST_FDT', scan._uclass)
uc = scan._uclass['UCLASS_TEST_FDT']
self.assertEqual({1: testfdt_node}, uc.alias_num_to_node)
self.assertEqual({'/some-bus/test': 1}, 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())