From 55e1278d5eca233421c92122e7fe2361eb010710 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 18 Jul 2023 07:24:03 -0600 Subject: [PATCH] dtoc: Allow inserting a list of nodes into another Provide a way to specify a phandle list of nodes which are to be inserted into an existing node. Signed-off-by: Simon Glass --- tools/dtoc/fdt.py | 22 +++++++++++++++++ tools/dtoc/test/dtoc_test_copy.dts | 14 ++++++++++- tools/dtoc/test_fdt.py | 39 ++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index f4d84083e4..fd0f3e94f5 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -748,6 +748,28 @@ class Node: dst.copy_node(node) return dst + def copy_subnodes_from_phandles(self, phandle_list): + """Copy subnodes of a list of nodes into another node + + Args: + phandle_list (list of int): List of phandles of nodes to copy + + For each node in the phandle list, its subnodes and their properties are + copied recursively. Note that it does not copy the node itself, nor its + properties. + """ + # Process in reverse order, since new nodes are inserted at the start of + # the destination's node list. We want them to appear in order of the + # phandle list + for phandle in phandle_list.__reversed__(): + parent = self.GetFdt().LookupPhandle(phandle) + tout.debug(f'adding template {parent.path} to node {self.path}') + for node in parent.subnodes.__reversed__(): + dst = self.copy_node(node) + + tout.debug(f'merge props from {parent.path} to {dst.path}') + self.merge_props(parent) + class Fdt: """Provides simple access to a flat device tree blob using libfdts. diff --git a/tools/dtoc/test/dtoc_test_copy.dts b/tools/dtoc/test/dtoc_test_copy.dts index 85e2c342a7..36faa9b72b 100644 --- a/tools/dtoc/test/dtoc_test_copy.dts +++ b/tools/dtoc/test/dtoc_test_copy.dts @@ -11,6 +11,7 @@ #address-cells = <1>; #size-cells = <1>; reference = <&over>; /* nake sure that the 'over' phandle exists */ + copy-list = <&another &base>; dest { bootph-all; @@ -46,7 +47,7 @@ }; }; - base { + base: base { compatible = "sandbox,i2c"; bootph-all; #address-cells = <1>; @@ -73,4 +74,15 @@ }; }; }; + + another: another { + new-prop = "hello"; + earlier { + wibble = <2>; + }; + + later { + fibble = <3>; + }; + }; }; diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py index ebc5297b50..3e54694eec 100755 --- a/tools/dtoc/test_fdt.py +++ b/tools/dtoc/test_fdt.py @@ -380,6 +380,45 @@ class TestNode(unittest.TestCase): dst = new_dtb.GetNode('/dest') do_copy_checks(new_dtb, dst, expect_none=False) + def test_copy_subnodes_from_phandles(self): + """Test copy_node() function""" + dtb = fdt.FdtScan(find_dtb_file('dtoc_test_copy.dts')) + + orig = dtb.GetNode('/') + node_list = fdt_util.GetPhandleList(orig, 'copy-list') + + dst = dtb.GetNode('/dest') + dst.copy_subnodes_from_phandles(node_list) + + pmic = dtb.GetNode('/dest/over') + self.assertTrue(pmic) + + subn = dtb.GetNode('/dest/first@0') + self.assertTrue(subn) + self.assertEqual({'a-prop', 'b-prop', 'reg'}, subn.props.keys()) + + self.assertEqual( + ['/dest/earlier', '/dest/later', '/dest/over', '/dest/first@0', + '/dest/second', '/dest/existing', '/dest/base'], + [n.path for n in dst.subnodes]) + + # Make sure that the phandle for 'over' is not copied + over = dst.FindNode('over') + print('keys', over.props.keys()) + self.assertNotIn('phandle', over.props.keys()) + + # Check the merged properties, first the base ones in '/dest' + expect = {'bootph-all', 'compatible', 'stringarray', 'longbytearray', + 'maybe-empty-int'} + + # Properties from 'base' + expect.update({'#address-cells', '#size-cells'}) + + # Properties from 'another' + expect.add('new-prop') + + self.assertEqual(expect, set(dst.props.keys())) + class TestProp(unittest.TestCase): """Test operation of the Prop class""" -- 2.39.5