[PATCH 17/20] binman: fit: Write the compatible string to configuration

Simon Glass sjg at chromium.org
Sat Jul 20 12:49:47 CEST 2024


FIT allows the FDT's root-node compatible string to be placed in a
configuration node to simplify and speed up finding the best match for
booting.

Add a new property to support this.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 tools/binman/entries.rst                 |  5 ++
 tools/binman/etype/fit.py                | 12 +++++
 tools/binman/ftest.py                    | 55 +++++++++++++++++++---
 tools/binman/test/334_fit_fdt_compat.dts | 60 ++++++++++++++++++++++++
 4 files changed, 125 insertions(+), 7 deletions(-)
 create mode 100644 tools/binman/test/334_fit_fdt_compat.dts

diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index dcacd298c6d..fd8edc64fa2 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -939,6 +939,7 @@ You can create config nodes in a similar way::
             firmware = "atf";
             loadables = "uboot";
             fdt = "fdt-SEQ";
+            fit,compatible;    // optional
         };
     };
 
@@ -948,6 +949,10 @@ for each of your two files.
 Note that if no devicetree files are provided (with '-a of-list' as above)
 then no nodes will be generated.
 
+The 'fit,compatible' property (if present) is replaced with the compatible
+string from the root node of the devicetree, so that things work correctly
+with FIT's configuration-matching algortihm.
+
 Generating nodes from an ELF file (split-elf)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index 8a25c784ef6..ab827d52066 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -171,6 +171,7 @@ class Entry_fit(Entry_section):
                 firmware = "atf";
                 loadables = "uboot";
                 fdt = "fdt-SEQ";
+                fit,compatible;
             };
         };
 
@@ -180,6 +181,10 @@ class Entry_fit(Entry_section):
     Note that if no devicetree files are provided (with '-a of-list' as above)
     then no nodes will be generated.
 
+    The 'fit,compatible' property is replaced with the compatible string from
+    the root node of the devicetree, so that things work correctly with FIT's
+    configuration-matching algortihm.
+
     Generating nodes from an ELF file (split-elf)
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -611,6 +616,13 @@ class Entry_fit(Entry_section):
                                 fsw.property('loadables', val.encode('utf-8'))
                             elif pname == 'fit,operation':
                                 pass
+                            elif pname == 'fit,compatible':
+                                fdt_phase = fdt_util.GetString(node, pname)
+                                data = tools.read_file(fname)
+                                fdt = Fdt.FromData(data)
+                                fdt.Scan()
+                                prop = fdt.GetRoot().props['compatible']
+                                fsw.property('compatible', prop.bytes)
                             elif pname.startswith('fit,'):
                                 self._raise_subnode(
                                     node, f"Unknown directive '{pname}'")
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 6e1e1e9b50b..d930e353faf 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -7490,6 +7490,24 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
             err,
             "Image '.*' is missing external blobs and is non-functional: .*")
 
+    def SetupAlternateDts(self):
+        """Compile the .dts test files for alternative-fdt
+
+        Returns:
+            tuple:
+                str: Test directory created
+                list of str: '.bin' files which we expect Binman to create
+        """
+        testdir = TestFunctional._MakeInputDir('dtb')
+        dtb_list = []
+        for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
+            tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
+            base = os.path.splitext(os.path.basename(fname))[0]
+            dtb_list.append(base + '.bin')
+            shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
+
+        return testdir, dtb_list
+
     def CheckAlternates(self, dts, phase, xpl_data):
         """Run the test for the alterative-fdt etype
 
@@ -7503,13 +7521,7 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
                 key: str filename
                 value: Fdt object
         """
-        testdir = TestFunctional._MakeInputDir('dtb')
-        dtb_list = []
-        for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
-            tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
-            base = os.path.splitext(os.path.basename(fname))[0]
-            dtb_list.append(base + '.bin')
-            shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
+        dtb_list = self.SetupAlternateDts()[1]
 
         entry_args = {
             f'{phase}-dtb': '1',
@@ -7614,6 +7626,35 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
         """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
         self.CheckFitFdt('333_fit_fdt_dir.dts', False)
 
+    def testFitFdtCompat(self):
+        """Test an image with an FIT with compatible in the config nodes"""
+        entry_args = {
+            'of-list': 'model1 model2',
+            'default-dt': 'model2',
+            }
+        testdir, dtb_list = self.SetupAlternateDts()
+        data = self._DoReadFileDtb(
+            '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
+            entry_args=entry_args, extra_indirs=[testdir])[0]
+
+        fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
+
+        fit = fdt.Fdt.FromData(fit_data)
+        fit.Scan()
+
+        cnode = fit.GetNode('/configurations')
+        self.assertIn('default', cnode.props)
+        self.assertEqual('config-2', cnode.props['default'].value)
+
+        for seq in range(1, 2):
+            name = f'config-{seq}'
+            fnode = fit.GetNode('/configurations/%s' % name)
+            self.assertIsNotNone(fnode)
+            self.assertIn('compatible', fnode.props.keys())
+            expected = 'one' if seq == 1 else 'two'
+            self.assertEqual(f'u-boot,model-{expected}',
+                             fnode.props['compatible'].value)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/334_fit_fdt_compat.dts b/tools/binman/test/334_fit_fdt_compat.dts
new file mode 100644
index 00000000000..3bf45c710db
--- /dev/null
+++ b/tools/binman/test/334_fit_fdt_compat.dts
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+		fit {
+			description = "test-desc";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				kernel {
+					description = "Vanilla Linux kernel";
+					type = "kernel";
+					arch = "ppc";
+					os = "linux";
+					compression = "gzip";
+					load = <00000000>;
+					entry = <00000000>;
+					hash-1 {
+						algo = "crc32";
+					};
+					hash-2 {
+						algo = "sha1";
+					};
+					u-boot {
+					};
+				};
+				@fdt-SEQ {
+					description = "fdt-NAME.dtb";
+					type = "flat_dt";
+					compression = "none";
+					hash {
+						algo = "sha256";
+					};
+				};
+			};
+
+			configurations {
+				default = "@config-DEFAULT-SEQ";
+				@config-SEQ {
+					description = "conf-NAME.dtb";
+					firmware = "uboot";
+					loadables = "atf";
+					fdt = "fdt-SEQ";
+					fit,firmware = "vpl";
+					fit,compatible;
+				};
+			};
+		};
+		u-boot-nodtb {
+		};
+	};
+};
-- 
2.34.1



More information about the U-Boot mailing list