In some cases it is desired for SPL to start TF-A instead of U-Boot
proper. Add support for a new property fit,firmware that picks a
valid entry and prepends the remaining valid entries to the
loadables list generated by the split-elf generator.

Signed-off-by: Jonas Karlman <jo...@kwiboo.se>
---
v3:
- Introduce new fit,firmware property to handle firmware selection
v2:
- New patch

 tools/binman/entries.rst                      | 16 +++-
 tools/binman/etype/fit.py                     | 62 ++++++++++--
 tools/binman/ftest.py                         | 44 +++++++++
 .../test/276_fit_firmware_loadables.dts       | 96 +++++++++++++++++++
 4 files changed, 205 insertions(+), 13 deletions(-)
 create mode 100644 tools/binman/test/276_fit_firmware_loadables.dts

diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index 78f95dae1a4e..7a04a613992d 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -721,6 +721,12 @@ split-elf
     fit,data
         Generates a `data = <...>` property with the contents of the segment
 
+    fit,firmware
+        Generates a `firmware = <...>` property. Provides a list of possible
+        nodes to be used as the `firmware` property value. The first valid
+        node is picked as the firmware. Any remaining valid nodes is
+        prepended to the `loadable` property generated by `fit,loadables`
+
     fit,loadables
         Generates a `loadable = <...>` property with a list of the generated
         nodes (including all nodes if this operation is used multiple times)
@@ -791,7 +797,7 @@ Here is an example showing ATF, TEE and a device tree all 
combined::
             @config-SEQ {
                 description = "conf-NAME.dtb";
                 fdt = "fdt-SEQ";
-                firmware = "u-boot";
+                fit,firmware = "atf-1", "u-boot";
                 fit,loadables;
             };
         };
@@ -846,15 +852,15 @@ is::
     configurations {
         default = "config-1";
         config-1 {
-            loadables = "atf-1", "atf-2", "atf-3", "tee-1", "tee-2";
+            loadables = "u-boot", "atf-2", "atf-3", "tee-1", "tee-2";
             description = "rk3399-firefly.dtb";
             fdt = "fdt-1";
-            firmware = "u-boot";
+            firmware = "atf-1";
         };
     };
 
-U-Boot SPL can then load the firmware (U-Boot proper) and all the loadables
-(ATF and TEE), then proceed with the boot.
+U-Boot SPL can then load the firmware (ATF) and all the loadables (U-Boot
+proper, ATF and TEE), then proceed with the boot.
 
 
 
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index bcb606f3f94c..cd2943533ce2 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -187,6 +187,12 @@ class Entry_fit(Entry_section):
         fit,data
             Generates a `data = <...>` property with the contents of the 
segment
 
+        fit,firmware
+            Generates a `firmware = <...>` property. Provides a list of 
possible
+            nodes to be used as the `firmware` property value. The first valid
+            node is picked as the firmware. Any remaining valid nodes is
+            prepended to the `loadable` property generated by `fit,loadables`
+
         fit,loadables
             Generates a `loadable = <...>` property with a list of the 
generated
             nodes (including all nodes if this operation is used multiple 
times)
@@ -257,7 +263,7 @@ class Entry_fit(Entry_section):
                 @config-SEQ {
                     description = "conf-NAME.dtb";
                     fdt = "fdt-SEQ";
-                    firmware = "u-boot";
+                    fit,firmware = "atf-1", "u-boot";
                     fit,loadables;
                 };
             };
@@ -312,15 +318,15 @@ class Entry_fit(Entry_section):
         configurations {
             default = "config-1";
             config-1 {
-                loadables = "atf-1", "atf-2", "atf-3", "tee-1", "tee-2";
+                loadables = "u-boot", "atf-2", "atf-3", "tee-1", "tee-2";
                 description = "rk3399-firefly.dtb";
                 fdt = "fdt-1";
-                firmware = "u-boot";
+                firmware = "atf-1";
             };
         };
 
-    U-Boot SPL can then load the firmware (U-Boot proper) and all the loadables
-    (ATF and TEE), then proceed with the boot.
+    U-Boot SPL can then load the firmware (ATF) and all the loadables (U-Boot
+    proper, ATF and TEE), then proceed with the boot.
     """
     def __init__(self, section, etype, node):
         """
@@ -510,6 +516,42 @@ class Entry_fit(Entry_section):
                 return
             fsw.property(pname, prop.bytes)
 
+        def _process_firmware_prop(node):
+            """Process optional fit,firmware property
+
+            Picks the first valid entry for use as the firmware, remaining 
valid
+            entries is prepended to loadables
+
+            Args:
+                node (Node): Generator node to process
+
+            Returns:
+                firmware (str): Firmware or None
+                result (list): List of remaining loadables
+            """
+            val = fdt_util.GetStringList(node, 'fit,firmware')
+            if val is None:
+                return None, self._loadables
+            valid_entries = list(self._loadables)
+            for name, entry in self.GetEntries().items():
+                missing = []
+                entry.CheckMissing(missing)
+                entry.CheckOptional(missing)
+                if not missing:
+                    valid_entries.append(name)
+            firmware = None
+            result = []
+            for name in val:
+                if name in valid_entries:
+                    if not firmware:
+                        firmware = name
+                    elif name not in result:
+                        result.append(name)
+            for name in self._loadables:
+                if name != firmware and name not in result:
+                    result.append(name)
+            return firmware, result
+
         def _gen_fdt_nodes(base_node, node, depth, in_images):
             """Generate FDT nodes
 
@@ -520,20 +562,24 @@ class Entry_fit(Entry_section):
             first.
 
             Args:
-                node (None): Generator node to process
+                node (Node): Generator node to process
                 depth: Current node depth (0 is the base 'fit' node)
                 in_images: True if this is inside the 'images' node, so that
                     'data' properties should be generated
             """
             if self._fdts:
+                firmware, fit_loadables = _process_firmware_prop(node)
                 # Generate nodes for each FDT
                 for seq, fdt_fname in enumerate(self._fdts):
                     node_name = node.name[1:].replace('SEQ', str(seq + 1))
                     fname = tools.get_input_filename(fdt_fname + '.dtb')
                     with fsw.add_node(node_name):
                         for pname, prop in node.props.items():
-                            if pname == 'fit,loadables':
-                                val = '\0'.join(self._loadables) + '\0'
+                            if pname == 'fit,firmware':
+                                if firmware:
+                                    fsw.property_string('firmware', firmware)
+                            elif pname == 'fit,loadables':
+                                val = '\0'.join(fit_loadables) + '\0'
                                 fsw.property('loadables', val.encode('utf-8'))
                             elif pname == 'fit,operation':
                                 pass
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index cd2757257178..0c4d34dfe480 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -6337,6 +6337,50 @@ fdt         fdtmap                Extract the devicetree 
blob from the fdtmap
         }
         self.assertEqual(expected, props)
 
+    def testFitFirmwareLoadables(self):
+        """Test an image with an FIT that use fit,firmware"""
+        if not elf.ELF_TOOLS:
+            self.skipTest('Python elftools not available')
+        entry_args = {
+            'of-list': 'test-fdt1',
+            'default-dt': 'test-fdt1',
+            'atf-bl31-path': 'bl31.elf',
+            'tee-os-path': 'missing.bin',
+        }
+        test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
+        data = self._DoReadFileDtb(
+            '276_fit_firmware_loadables.dts',
+            entry_args=entry_args,
+            extra_indirs=[test_subdir])[0]
+
+        dtb = fdt.Fdt.FromData(data)
+        dtb.Scan()
+
+        node = dtb.GetNode('/configurations/conf-uboot-1')
+        self.assertEqual('u-boot', node.props['firmware'].value)
+        self.assertEqual(['atf-1', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
+        node = dtb.GetNode('/configurations/conf-atf-1')
+        self.assertEqual('atf-1', node.props['firmware'].value)
+        self.assertEqual(['u-boot', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
+        node = dtb.GetNode('/configurations/conf-missing-uboot-1')
+        self.assertEqual('u-boot', node.props['firmware'].value)
+        self.assertEqual(['atf-1', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
+        node = dtb.GetNode('/configurations/conf-missing-atf-1')
+        self.assertEqual('atf-1', node.props['firmware'].value)
+        self.assertEqual(['u-boot', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
+        node = dtb.GetNode('/configurations/conf-missing-tee-1')
+        self.assertEqual('atf-1', node.props['firmware'].value)
+        self.assertEqual(['u-boot', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/276_fit_firmware_loadables.dts 
b/tools/binman/test/276_fit_firmware_loadables.dts
new file mode 100644
index 000000000000..4428e6a7e8e8
--- /dev/null
+++ b/tools/binman/test/276_fit_firmware_loadables.dts
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               fit {
+                       description = "test desc";
+                       #address-cells = <1>;
+                       fit,fdt-list = "of-list";
+
+                       images {
+                               u-boot {
+                                       description = "test u-boot";
+                                       type = "standalone";
+                                       arch = "arm64";
+                                       os = "u-boot";
+                                       compression = "none";
+                                       load = <0x00000000>;
+                                       entry = <0x00000000>;
+
+                                       u-boot-nodtb {
+                                       };
+                               };
+                               tee {
+                                       description = "test tee";
+                                       type = "tee";
+                                       arch = "arm64";
+                                       os = "tee";
+                                       compression = "none";
+                                       load = <0x00200000>;
+
+                                       tee-os {
+                                               optional;
+                                       };
+                               };
+                               @atf-SEQ {
+                                       fit,operation = "split-elf";
+                                       description = "test tf-a";
+                                       type = "firmware";
+                                       arch = "arm64";
+                                       os = "arm-trusted-firmware";
+                                       compression = "none";
+                                       fit,load;
+                                       fit,entry;
+                                       fit,data;
+
+                                       atf-bl31 {
+                                       };
+                               };
+                               @fdt-SEQ {
+                                       description = "test fdt";
+                                       type = "flat_dt";
+                                       compression = "none";
+                               };
+                       };
+
+                       configurations {
+                               default = "@conf-uboot-DEFAULT-SEQ";
+                               @conf-uboot-SEQ {
+                                       description = "uboot config";
+                                       fdt = "fdt-SEQ";
+                                       fit,firmware = "u-boot";
+                                       fit,loadables;
+                               };
+                               @conf-atf-SEQ {
+                                       description = "atf config";
+                                       fdt = "fdt-SEQ";
+                                       fit,firmware = "atf-1", "u-boot";
+                                       fit,loadables;
+                               };
+                               @conf-missing-uboot-SEQ {
+                                       description = "missing uboot config";
+                                       fdt = "fdt-SEQ";
+                                       fit,firmware = "missing-1", "u-boot";
+                                       fit,loadables;
+                               };
+                               @conf-missing-atf-SEQ {
+                                       description = "missing atf config";
+                                       fdt = "fdt-SEQ";
+                                       fit,firmware = "missing-1", "atf-1", 
"u-boot";
+                                       fit,loadables;
+                               };
+                               @conf-missing-tee-SEQ {
+                                       description = "missing tee config";
+                                       fdt = "fdt-SEQ";
+                                       fit,firmware = "atf-1", "u-boot", "tee";
+                                       fit,loadables;
+                               };
+                       };
+               };
+       };
+};
-- 
2.39.1

Reply via email to