Skip to contentSkip to conversation

binman: fit: Compress generated fdt images and use it on Rockchip

PATCH In review Petr Hodina 4 participants 19 messages Oct 17 – Nov 11

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v2 cover binman: fit: Compress generated fdt images and use it on Rockchip

Entry_fit's @fdt-SEQ generator always embeds the raw .dtb. Add a 'fit,compress' property so binman can compress it with any algorithm FIT defines (xz is rejected) and set 'compression' to match.

Add a generic SPL_FIT_FDT_COMP choice (none, LZMA, gzip: what the SPL FIT loader can currently decompress) and use it on Rockchip.

The default is none so no in-tree board changes.

---
Changes in v2:
- Use a binman-level 'fit,compress' property instead of acting on 'compression'
- Support all algorithms binman knows via a shared bintool-name helper
- Register the bintool in AddBintools() and handle a missing tool, reject 'xz'
- Split the test device trees and tests into their own patches
- Document the property in the Entry_fit docstring
- Expand the Rockchip commit message
- Add a generic SPL_FIT_FDT_COMP choice in boot/Kconfig used by Rockchip
- Link to v1: https://patch.msgid.link/20261010-b4-binman-fit-fdt-compression-v1-0-4465558758cc@protonmail.com

To: [email protected]

Cc Simon Glass <[email protected]>
Cc Alper Nebi Yasak <[email protected]>
Cc Tom Rini <[email protected]>
Cc Quentin Schulz <[email protected]>
Cc Marek Vasut <[email protected]>
Cc Wojciech Dubowik <[email protected]>
Cc Ilias Apalodimas <[email protected]>
Cc Philipp Tomsich <[email protected]>
Cc Kever Yang <[email protected]>
Cc Jonas Karlman <[email protected]>
Cc Petr Pavlata <[email protected]>
Cc David Heidelberg <[email protected]>
Cc Alexey Charkov <[email protected]>
Cc James Hilliard <[email protected]>
Cc Aristo Chen <[email protected]>
Cc Philippe Reynes <[email protected]>
Cc Daniel Golle <[email protected]>
Cc Johan Jonker <[email protected]>
Cc Quentin Schulz <[email protected]>

---
Petr Hodina (6):
binman: Factor out the compression bintool lookup
binman: fit: Add fit,compress for generated fdt images
binman: test: Add fit,compress device trees
binman: test: Add tests for fit,compress
boot: Add a choice for the compression of the FDT in the FIT
rockchip: Allow compression of the FDT in the FIT

 arch/arm/dts/rockchip-u-boot.dtsi          | 15 ++++++-
 boot/Kconfig                               | 32 ++++++++++++++
 tools/binman/entry.py                      | 27 +++++++++---
 tools/binman/etype/fit.py                  | 67 ++++++++++++++++++++++++++++++
 tools/binman/ftest.py                      | 44 ++++++++++++++++++++
 tools/binman/test/fit/fdt_compress.dts     | 24 +++++++++++
 tools/binman/test/fit/fdt_compress_bad.dts | 24 +++++++++++
 tools/binman/test/fit/fdt_compress_xz.dts  | 24 +++++++++++
 8 files changed, 250 insertions(+), 7 deletions(-)

---
base-commit: 8d534cec0cc0109a37c0ded8854da03f1526dc0e
change-id: 20261010-b4-binman-fit-fdt-compression-3166bcbd15b5

Best regards,

Signature · 1 line
Petr Hodina <[email protected]>
#1 lore raw

PATCH v2 1/6 binman: Factor out the compression bintool lookup

Move the compression-algorithm-to-bintool mapping out of Entry.AddBintools() into get_comp_bintool_name() so that it can be shared with other etypes.

---
 tools/binman/entry.py | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)
tools/binman/entry.py +21 -6
index 9b39c711889..5eef1d57be9 100644
@@ -1297,12 +1297,27 @@ features to produce new behaviours.
         """
         algo = self.compress
         if algo != 'none':
-            algos = ['bzip2', 'gzip', 'lz4', 'lzma', 'lzo', 'xz', 'zstd']
-            if algo not in algos:
-                raise ValueError("Unknown algorithm '%s'" % algo)
-            names = {'lzma': 'lzma_alone', 'lzo': 'lzop'}
-            name = names.get(self.compress, self.compress)
-            self.comp_bintool = self.AddBintool(btools, name)
+            self.comp_bintool = self.AddBintool(
+                btools, self.get_comp_bintool_name(algo))
+
+    @staticmethod
+    def get_comp_bintool_name(algo):
+        """Get the name of the bintool which handles a compression algorithm
+
+        Args:
+            algo (str): Compression algorithm, e.g. 'gzip'
+
+        Returns:
+            str: Name of bintool
+
+        Raises:
+            ValueError: if the algorithm is not supported
+        """
+        algos = ['bzip2', 'gzip', 'lz4', 'lzma', 'lzo', 'xz', 'zstd']
+        if algo not in algos:
+            raise ValueError("Unknown algorithm '%s'" % algo)
+        names = {'lzma': 'lzma_alone', 'lzo': 'lzop'}
+        return names.get(algo, algo)
 
     @classmethod
     def AddBintool(self, tools, name):
Signature · 1 line
2.55.0
Reviewed-by on v2 1/6
#2 lore raw

Re: [PATCH v2 1/6] binman: Factor out the compression bintool lookup

Quoted 10 lines · On 2026-10-17T07:38:59, Petr Hodina via B4 Relay…

binman: Factor out the compression bintool lookup

Move the compression-algorithm-to-bintool mapping out of Entry.AddBintools() into get_comp_bintool_name() so that it can be shared with other etypes.

tools/binman/entry.py | 27 +++++++++++++++++++++------

 1 file changed, 21 insertions(+), 6 deletions(-)
#3 lore raw

Re: [PATCH v2 1/6] binman: Factor out the compression bintool lookup

In reply to Petr Hodina

Hi Petr,

Quoted 36 lines · On 10/17/26 9:39 AM, Petr Hodina via B4 Relay wrote:

From: Petr Hodina <[email protected]>

Move the compression-algorithm-to-bintool mapping out of Entry.AddBintools() into get_comp_bintool_name() so that it can be shared with other etypes.

---
  tools/binman/entry.py | 27 +++++++++++++++++++++------
  1 file changed, 21 insertions(+), 6 deletions(-)
tools/binman/entry.py +11 -6
index 9b39c711889..5eef1d57be9 100644
@@ -1297,12 +1297,27 @@ features to produce new behaviours.
          """
          algo = self.compress
          if algo != 'none':
-            algos = ['bzip2', 'gzip', 'lz4', 'lzma', 'lzo', 'xz', 'zstd']
-            if algo not in algos:
-                raise ValueError("Unknown algorithm '%s'" % algo)
-            names = {'lzma': 'lzma_alone', 'lzo': 'lzop'}
-            name = names.get(self.compress, self.compress)
-            self.comp_bintool = self.AddBintool(btools, name)
+            self.comp_bintool = self.AddBintool(
+                btools, self.get_comp_bintool_name(algo))
+
+    @staticmethod
+    def get_comp_bintool_name(algo):
+        """Get the name of the bintool which handles a compression algorithm
+
+        Args:
+            algo (str): Compression algorithm, e.g. 'gzip'
+
+        Returns:

tools/binman/entry.py features to produce new behaviours. · line 1320

Quoted 10 lines
tools/binman/entry.py +10 -0
+            str: Name of bintool
+
+        Raises:
+            ValueError: if the algorithm is not supported
+        """
+        algos = ['bzip2', 'gzip', 'lz4', 'lzma', 'lzo', 'xz', 'zstd']
+        if algo not in algos:
+            raise ValueError("Unknown algorithm '%s'" % algo)
+        names = {'lzma': 'lzma_alone', 'lzo': 'lzop'}
+        return names.get(algo, algo)

I can't help but think this is the wrong way to handle that. Why should Entry deal with Bintool stuff?

I'm thinking this is best handled by at the very least a static method in Bintool instead.

In a future patch, I think it would also make sense to not have this hardcoded in Bintool class at all and have every BintoolPacker report which algorithms they handle so we don't have to keep a list of supported algorithms outside of the one class it matters, the one supporting the algorithm.

Cheers,
Quentin

#4 lore raw

PATCH v2 2/6 binman: fit: Add fit,compress for generated fdt images

In reply to Petr Hodina

The 'compression' property of a FIT image is only metadata.

Add a 'fit,compress' property for generator nodes. It names the algorithm so binman compresses each .dtb with it and writes the algorithm to 'compression' in the generated node.

Any algorithm known to Entry.AddBintools() is accepted.

Register the needed bintools in Entry_fit.AddBintools() and report a missing one in the usual way instead of failing.

Document the property.

---
 tools/binman/etype/fit.py | 67 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)
tools/binman/etype/fit.py +67 -0
index 4657ed1fd76..a81e3a1de0e 100644
@@ -274,6 +274,29 @@ class Entry_fit(Entry_section):
     string from the root node of the devicetree, so that things work correctly
     with FIT's configuration-matching algortihm.
 
+    Compressing the FDT images
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    The 'compression' property of an image node is copied into the FIT as
+    metadata only. It tells the loader how the data is stored, but binman does
+    not touch the data.
+    For generated FDT nodes, the 'fit,compress' property can be used to ask
+    binman to compress the .dtb as well. The algorithm is written to
+    the 'compression' property of each generated node, so it should
+    not also be given there::
+
+        images {
+            @fdt-SEQ {
+                description = "fdt-NAME";
+                type = "flat_dt";
+                fit,compress = "lzma";
+            };
+        };
+
+    Any algorithm supported by binman can be used (see the 'compress' property
+    of entries) except "xz" which FIT does not define or "none". The matching
+    compression tool must be installed.
+
     Dealing with phases
     ~~~~~~~~~~~~~~~~~~~
 
@@ -746,6 +769,26 @@ class Entry_fit(Entry_section):
 
         return tools.read_file(output_fname)
 
+    def _compress_fdt(self, algo, data):
+        """Compress the data of a generated fdt node
+
+        Args:
+            algo (str): Compression algorithm
+            data (bytes): Data to compress
+
+        Returns:
+            bytes: Compressed data
+
+        Raises:
+            ValueError: if the compression tool is not available
+        """
+        btool = self.fdt_comp_bintools[algo]
+        if not btool.is_present():
+            raise ValueError(
+                f"Cannot compress fdt with '{algo}': tool '{btool.name}' is "
+                f"missing")
+        return btool.compress(data)
+
     def _raise_subnode(self, node, msg):
         """Raise an error with a paticular FIT subnode
 
@@ -883,6 +926,7 @@ class Entry_fit(Entry_section):
                     else:
                         fname = tools.get_input_filename(fdt_fname + '.dtb')
                     fdt_phase = None
+                    compress = 'none'
                     with fsw.add_node(node_name):
                         for pname, prop in node.props.items():
                             if pname == 'fit,firmware':
@@ -902,6 +946,9 @@ class Entry_fit(Entry_section):
                                 fsw.property('compatible', prop.bytes)
                             elif pname == 'fit,fdt-phase':
                                 fdt_phase = fdt_util.GetString(node, pname)
+                            elif pname == 'fit,compress':
+                                compress = fdt_util.GetString(node, pname)
+                                fsw.property_string('compression', compress)
                             elif pname.startswith('fit,'):
                                 self._raise_subnode(
                                     node, f"Unknown directive '{pname}'")
@@ -922,6 +969,8 @@ class Entry_fit(Entry_section):
                                 data = tools.read_file(phase_fname)
                             else:
                                 data = tools.read_file(fname)
+                            if compress != 'none':
+                                data = self._compress_fdt(compress, data)
                             fsw.property('data', data)
 
                         for subnode in node.subnodes:
@@ -1148,10 +1197,28 @@ class Entry_fit(Entry_section):
             entry.SetImagePos(image_pos + self.offset)
 
     def AddBintools(self, btools):
+        # Add the tool for each algorithm requested by a generator node
         super().AddBintools(btools)
         self.mkimage = self.AddBintool(btools, 'mkimage')
         self.fdtgrep = self.AddBintool(btools, 'fdtgrep')
 
+        self.fdt_comp_bintools = {}
+        def _add_comp_bintools(node):
+            for prop in node.props.values():
+                if prop.name == 'fit,compress' and prop.value != 'none':
+                    if prop.value == 'xz':
+                        self._raise_subnode(
+                            node, "fit,compress 'xz' is not a FIT compression")
+                    try:
+                        name = self.get_comp_bintool_name(prop.value)
+                    except ValueError as exc:
+                        self._raise_subnode(node, str(exc))
+                    self.fdt_comp_bintools[prop.value] = self.AddBintool(
+                        btools, name)
+            for subnode in node.subnodes:
+                _add_comp_bintools(subnode)
+        _add_comp_bintools(self._node)
+
     def CheckMissing(self, missing_list):
         # We must use our private entry list for this since generator nodes
         # which are removed from self._entries will otherwise not show up as
Signature · 1 line
2.55.0
#5 lore raw

Re: [PATCH v2 2/6] binman: fit: Add fit, compress for generated fdt images

Hi Petr,

Quoted 4 lines · On 2026-10-17T07:38:59, Petr Hodina via B4 Relay…

binman: fit: Add fit,compress for generated fdt images

The 'compression' property of a FIT image is only metadata.

Quoted 8 lines

Add a 'fit,compress' property for generator nodes. It names the algorithm so binman compresses each .dtb with it and writes the algorithm to 'compression' in the generated node.

Any algorithm known to Entry.AddBintools() is accepted.

Register the needed bintools in Entry_fit.AddBintools() and report a missing one in the usual way instead of failing.

The code does not match this. _compress_fdt() raises ValueError when the tool is missing, and testFitFdtCompressMissing asserts that behaviour even with allow_missing=True. The usual pattern in binman (see Entry.CompressData() and the mkimage path above in this same file) is to call record_missing_bintool() and emit placeholder data so the build completes and the user gets a single consolidated missing-tools report. Please either make _compress_fdt() follow that pattern, or reword the commit message to say that a missing compressor is a hard error.

tools/binman/etype/fit.py class Entry_fit(Entry_section): · line 275

Quoted 12 lines

Document the property.

tools/binman/etype/fit.py | 67 +++++++++++++++++++++++++++++++++++++++++++++++

 1 file changed, 67 insertions(+)
tools/binman/etype/fit.py +2 -0
@@ -274,6 +274,29 @@ class Entry_fit(Entry_section):
+    Any algorithm supported by binman can be used (see the 'compress' property
+    of entries) except "xz" which FIT does not define or "none".

The "or 'none'" tail reads as if 'none' were also excluded, which it isn't — it's the default. Please reword, e.g. "any algorithm supported by binman (see the 'compress' property of entries) except 'xz', which FIT does not define".

tools/binman/etype/fit.py class Entry_fit(Entry_section): · line 1201

Quoted 7 lines
tools/binman/etype/fit.py +1 -0
@@ -1148,10 +1197,28 @@ class Entry_fit(Entry_section):
     def AddBintools(self, btools):
+        # Add the tool for each algorithm requested by a generator node
         super().AddBintools(btools)
         self.mkimage = self.AddBintool(btools, 'mkimage')
         self.fdtgrep = self.AddBintool(btools, 'fdtgrep')

The comment belongs on the fdt_comp_bintools block below, not up here — as it stands it reads as if it applies to mkimage/fdtgrep.

Quoted 8 lines
tools/binman/etype/fit.py +6 -0
@@ -1148,10 +1197,28 @@ class Entry_fit(Entry_section):
+        self.fdt_comp_bintools = {}
+        def _add_comp_bintools(node):
+            for prop in node.props.values():
+                if prop.name == 'fit,compress' and prop.value != 'none':
+                    if prop.value == 'xz':
+                        self._raise_subnode(

tools/binman/etype/fit.py class Entry_fit(Entry_section): · line 1212

Quoted 10 lines
tools/binman/etype/fit.py +10 -0
+                            node, "fit,compress 'xz' is not a FIT compression")
+                    try:
+                        name = self.get_comp_bintool_name(prop.value)
+                    except ValueError as exc:
+                        self._raise_subnode(node, str(exc))
+                    self.fdt_comp_bintools[prop.value] = self.AddBintool(
+                        btools, name)
+            for subnode in node.subnodes:
+                _add_comp_bintools(subnode)
+        _add_comp_bintools(self._node)

Just to check — this walks every subnode and acts on any 'fit,compress' prop, including on a plain (non-generator) image node, which the _build_input() path never honours. Worth restricting to generator nodes (name starting with '@') so the two sides stay in sync? Otherwise someone will set fit,compress on an ordinary image and silently get no compression.

Regards,
Simon

#6 lore raw

Re: [PATCH v2 2/6] binman: fit: Add fit,compress for generated fdt images

In reply to Petr Hodina

Hi Petr,

Quoted 28 lines · On 10/17/26 9:39 AM, Petr Hodina via B4 Relay wrote:

From: Petr Hodina <[email protected]>

The 'compression' property of a FIT image is only metadata.

Add a 'fit,compress' property for generator nodes. It names the algorithm so binman compresses each .dtb with it and writes the algorithm to 'compression' in the generated node.

Any algorithm known to Entry.AddBintools() is accepted.

Register the needed bintools in Entry_fit.AddBintools() and report a missing one in the usual way instead of failing.

Document the property.

---
  tools/binman/etype/fit.py | 67 +++++++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 67 insertions(+)
tools/binman/etype/fit.py +0 -0
index 4657ed1fd76..a81e3a1de0e 100644
@@ -274,6 +274,29 @@ class Entry_fit(Entry_section):
      string from the root node of the devicetree, so that things work correctly
      with FIT's configuration-matching algortihm.
 

tools/binman/etype/fit.py class Entry_fit(Entry_section): · line 286

Quoted 10 lines
tools/binman/etype/fit.py +10 -0
+    Compressing the FDT images
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    The 'compression' property of an image node is copied into the FIT as
+    metadata only. It tells the loader how the data is stored, but binman does
+    not touch the data.
+    For generated FDT nodes, the 'fit,compress' property can be used to ask
+    binman to compress the .dtb as well. The algorithm is written to
+    the 'compression' property of each generated node, so it should
+    not also be given there::

I'm wondering if we shouldn't have a different logic. Keep compression as the property, and the user must set it when they want to use compression. Then, set fit,compress in the node if you want U-Boot to actually act on it, otherwise it's left in the default format. This allows us to simply trust what the user puts in the compression property, which is ruled by the FIT spec, so if they put something wrong there, their fault.

In either case, I'm wondering if there could be a need for having a compression = "none" but still have U-Boot compress it. According to the spec:

"""
If the data is compressed but it should not be uncompressed by the loader (e.g. compressed ramdisk <pair: ramdisk; compressed), this should also be set to “none”. """

Then we need to decorrelate both and they mean different things.

Cheers,
Quentin

#7 lore raw

PATCH v2 3/6 binman: test: Add fit,compress device trees

In reply to Petr Hodina

Add two minimal device trees with a FIT containing an @fdt-SEQ template which uses 'fit,compress': one with "lzma", another on with "xz" which is currently not supported in SPL and one with an unknown algorithm.

They are used by the tests in the next patch.

---
 tools/binman/test/fit/fdt_compress.dts     | 24 ++++++++++++++++++++++++
 tools/binman/test/fit/fdt_compress_bad.dts | 24 ++++++++++++++++++++++++
 tools/binman/test/fit/fdt_compress_xz.dts  | 24 ++++++++++++++++++++++++
 3 files changed, 72 insertions(+)
tools/binman/test/fit/fdt_compress.dts new file +24 -0
new file mode 100644
index 00000000000..77c38fe9e05
@@ -0,0 +1,24 @@
+// 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 {
+				@fdt-SEQ {
+					description = "fdt-NAME.dtb";
+					type = "flat_dt";
+					fit,compress = "lzma";
+				};
+			};
+		};
+	};
+};
tools/binman/test/fit/fdt_compress_bad.dts new file +24 -0
new file mode 100644
index 00000000000..93ea20272a4
@@ -0,0 +1,24 @@
+// 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 {
+				@fdt-SEQ {
+					description = "fdt-NAME.dtb";
+					type = "flat_dt";
+					fit,compress = "bad";
+				};
+			};
+		};
+	};
+};
tools/binman/test/fit/fdt_compress_xz.dts new file +24 -0
new file mode 100644
index 00000000000..6c2d1c89399
@@ -0,0 +1,24 @@
+// 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 {
+				@fdt-SEQ {
+					description = "fdt-NAME.dtb";
+					type = "flat_dt";
+					fit,compress = "xz";
+				};
+			};
+		};
+	};
+};
Signature · 1 line
2.55.0
Reviewed-by on v2 3/6
#8 lore raw

Re: [PATCH v2 3/6] binman: test: Add fit,compress device trees

Quoted 6 lines · On 2026-10-17T07:38:59, Petr Hodina via B4 Relay…

binman: test: Add fit,compress device trees

Add two minimal device trees with a FIT containing an @fdt-SEQ template which uses 'fit,compress': one with "lzma", another on with "xz" which is currently not supported in SPL and one with an unknown algorithm.

Quoted 8 lines

They are used by the tests in the next patch.

tools/binman/test/fit/fdt_compress.dts | 24 ++++++++++++++++++++++++

 tools/binman/test/fit/fdt_compress_bad.dts | 24 ++++++++++++++++++++++++
 tools/binman/test/fit/fdt_compress_xz.dts  | 24 ++++++++++++++++++++++++
 3 files changed, 72 insertions(+)
#9 lore raw

PATCH v2 4/6 binman: test: Add tests for fit,compress

In reply to Petr Hodina

Check that generated fdt images are compressed and that 'compression' is set from 'fit,compress', that an unknown algorithm is rejected and that a missing compression tool is reported.

---
 tools/binman/ftest.py | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
tools/binman/ftest.py +44 -0
index 8caf275d466..fdb22b0965f 100644
@@ -4357,6 +4357,50 @@ class TestFunctional(unittest.TestCase):
         """Test an image with an FIT with multiple FDT images"""
         self.CheckFitFdt()
 
+    def _FitFdtCompress(self, fname):
+        entry_args = {'of-list': 'test-fdt1 test-fdt2'}
+        extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
+        return self._DoReadFileDtb(fname, entry_args=entry_args,
+                                   extra_indirs=extra_indirs)[0]
+
+    def testFitFdtCompress(self):
+        """Test that fit,compress compresses generated fdt images"""
+        bintool = self.comp_bintools['lzma_alone']
+        self._CheckBintool(bintool)
+        data = self._FitFdtCompress('fit/fdt_compress.dts')
+        dtb = fdt.Fdt.FromData(data)
+        dtb.Scan()
+        for seq, expected in ((1, TEST_FDT1_DATA), (2, TEST_FDT2_DATA)):
+            fnode = dtb.GetNode('/images/fdt-%d' % seq)
+            self.assertEqual('lzma', fnode.props['compression'].value)
+            self.assertNotIn('fit,compress', fnode.props)
+            comp = fnode.props['data'].bytes
+            self.assertNotEqual(expected, comp)
+            self.assertEqual(expected, bintool.decompress(comp))
+
+    def testFitFdtCompressBad(self):
+        """Test an unsupported fdt compression algorithm"""
+        with self.assertRaises(ValueError) as e:
+            self._FitFdtCompress('fit/fdt_compress_bad.dts')
+        self.assertIn("Unknown algorithm 'bad'", str(e.exception))
+
+    def testFitFdtCompressXz(self):
+        """Test that xz is rejected as it is not a FIT compression"""
+        with self.assertRaises(ValueError) as e:
+            self._FitFdtCompress('fit/fdt_compress_xz.dts')
+        self.assertIn("fit,compress 'xz' is not a FIT compression",
+                      str(e.exception))
+
+    def testFitFdtCompressMissing(self):
+        """Test that a missing compression tool is an error"""
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile('fit/fdt_compress.dts', allow_missing=True,
+                             force_missing_bintools='lzma_alone',
+                             entry_args={'of-list': 'test-fdt1 test-fdt2'},
+                             extra_indirs=[os.path.join(self._indir,
+                                                        TEST_FDT_SUBDIR)])
+        self.assertIn("tool 'lzma_alone' is missing", str(e.exception))
+
     def testFitFdtMissingList(self):
         """Test handling of a missing 'of-list' entry arg"""
         with self.assertRaises(ValueError) as e:
Signature · 1 line
2.55.0
#10 lore raw

Re: [PATCH v2 4/6] binman: test: Add tests for fit,compress

Hi Petr,

Quoted 15 lines · On 2026-10-17T07:38:59, Petr Hodina via B4 Relay…

binman: test: Add tests for fit,compress

Check that generated fdt images are compressed and that 'compression' is set from 'fit,compress', that an unknown algorithm is rejected and that a missing compression tool is reported.

tools/binman/ftest.py | 44 ++++++++++++++++++++++++++++++++++++++++++++

 1 file changed, 44 insertions(+)
tools/binman/ftest.py +4 -0
+    def testFitFdtCompress(self):
+        """Test that fit,compress compresses generated fdt images"""
+        bintool = self.comp_bintools['lzma_alone']
+        self._CheckBintool(bintool)

tools/binman/ftest.py class TestFunctional(unittest.TestCase): · line 4379

Quoted 10 lines
tools/binman/ftest.py +10 -0
+        data = self._FitFdtCompress('fit/fdt_compress.dts')
+        dtb = fdt.Fdt.FromData(data)
+        dtb.Scan()
+        for seq, expected in ((1, TEST_FDT1_DATA), (2, TEST_FDT2_DATA)):
+            fnode = dtb.GetNode('/images/fdt-%d' % seq)
+            self.assertEqual('lzma', fnode.props['compression'].value)
+            self.assertNotIn('fit,compress', fnode.props)
+            comp = fnode.props['data'].bytes
+            self.assertNotEqual(expected, comp)
+            self.assertEqual(expected, bintool.decompress(comp))

Only lzma is exercised on the happy path. It would be worth adding a second dts (say gzip) and a parallel test, so the shared bintool lookup from patch 1 is covered against regressions where a specific algorithm name is not handled. What do you think?

Regards,
Simon

#11 lore raw

Re: [PATCH v2 4/6] binman: test: Add tests for fit,compress

In reply to Petr Hodina

Hi Petr,

Squash with patch 3 please.

Quoted 67 lines · On 10/17/26 9:39 AM, Petr Hodina via B4 Relay wrote:

From: Petr Hodina <[email protected]>

Check that generated fdt images are compressed and that 'compression' is set from 'fit,compress', that an unknown algorithm is rejected and that a missing compression tool is reported.

---
  tools/binman/ftest.py | 44 ++++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 44 insertions(+)
tools/binman/ftest.py +44 -0
index 8caf275d466..fdb22b0965f 100644
@@ -4357,6 +4357,50 @@ class TestFunctional(unittest.TestCase):
          """Test an image with an FIT with multiple FDT images"""
          self.CheckFitFdt()
 
+    def _FitFdtCompress(self, fname):
+        entry_args = {'of-list': 'test-fdt1 test-fdt2'}
+        extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
+        return self._DoReadFileDtb(fname, entry_args=entry_args,
+                                   extra_indirs=extra_indirs)[0]
+
+    def testFitFdtCompress(self):
+        """Test that fit,compress compresses generated fdt images"""
+        bintool = self.comp_bintools['lzma_alone']
+        self._CheckBintool(bintool)
+        data = self._FitFdtCompress('fit/fdt_compress.dts')
+        dtb = fdt.Fdt.FromData(data)
+        dtb.Scan()
+        for seq, expected in ((1, TEST_FDT1_DATA), (2, TEST_FDT2_DATA)):
+            fnode = dtb.GetNode('/images/fdt-%d' % seq)
+            self.assertEqual('lzma', fnode.props['compression'].value)
+            self.assertNotIn('fit,compress', fnode.props)
+            comp = fnode.props['data'].bytes
+            self.assertNotEqual(expected, comp)
+            self.assertEqual(expected, bintool.decompress(comp))
+
+    def testFitFdtCompressBad(self):
+        """Test an unsupported fdt compression algorithm"""
+        with self.assertRaises(ValueError) as e:
+            self._FitFdtCompress('fit/fdt_compress_bad.dts')
+        self.assertIn("Unknown algorithm 'bad'", str(e.exception))
+
+    def testFitFdtCompressXz(self):
+        """Test that xz is rejected as it is not a FIT compression"""
+        with self.assertRaises(ValueError) as e:
+            self._FitFdtCompress('fit/fdt_compress_xz.dts')
+        self.assertIn("fit,compress 'xz' is not a FIT compression",
+                      str(e.exception))
+
+    def testFitFdtCompressMissing(self):
+        """Test that a missing compression tool is an error"""
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile('fit/fdt_compress.dts', allow_missing=True,
+                             force_missing_bintools='lzma_alone',
+                             entry_args={'of-list': 'test-fdt1 test-fdt2'},
+                             extra_indirs=[os.path.join(self._indir,
+                                                        TEST_FDT_SUBDIR)])
+        self.assertIn("tool 'lzma_alone' is missing", str(e.exception))
+
      def testFitFdtMissingList(self):
          """Test handling of a missing 'of-list' entry arg"""
          with self.assertRaises(ValueError) as e:
#12 lore raw

PATCH v2 5/6 boot: Add a choice for the compression of the FDT in the FIT

In reply to Petr Hodina

Add SPL_FIT_FDT_COMP so a board can select how binman compresses the devicetrees in its FIT (none, LZMA or gzip). LZMA and gzip are the only algorithms the SPL FIT loader can decompress. The default is none.

---
 boot/Kconfig | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
boot/Kconfig +32 -0
index 8fcdc36c931..b84a75062b4 100644
@@ -236,6 +236,38 @@ config SPL_FIT_FULL_CHECK
 	  advantage of bugs or omissions in the code. This includes a bad
 	  structure, multiple root nodes and the like.
 
+choice
+	prompt "Compression of the FDT in the FIT"
+	depends on SPL_FIT
+	default SPL_FIT_FDT_COMP_NONE
+	help
+	  Select how binman compresses the devicetrees in the FIT. This is
+	  independent of the compression of U-Boot itself. SPL must be able to
+	  decompress the chosen algorithm. Only boards whose binman description
+	  uses the fit,compress property are affected.
+
+config SPL_FIT_FDT_COMP_NONE
+	bool "None"
+	help
+	  Do not compress the devicetrees. This needs no decompression support
+	  in SPL but makes the FIT larger.
+
+config SPL_FIT_FDT_COMP_LZMA
+	bool "LZMA"
+	depends on SPL_LZMA
+	help
+	  Compress the devicetrees with LZMA. This gives the smallest FIT but
+	  needs the most time and memory to decompress in SPL.
+
+config SPL_FIT_FDT_COMP_GZIP
+	bool "gzip"
+	depends on SPL_GZIP
+	help
+	  Compress the devicetrees with gzip. This decompresses faster than
+	  LZMA in SPL but the FIT is larger.
+
+endchoice
+
 config SPL_FIT_SIGNATURE
 	bool "Enable signature verification of FIT firmware within SPL"
 	depends on SPL_DM
Signature · 1 line
2.55.0
#13 lore raw

Re: [PATCH v2 5/6] boot: Add a choice for the compression of the FDT in the FIT

Hi Petr,

Quoted 5 lines · On 2026-10-17T07:38:59, Petr Hodina via B4 Relay…

boot: Add a choice for the compression of the FDT in the FIT

Add SPL_FIT_FDT_COMP so a board can select how binman compresses the devicetrees in its FIT (none, LZMA or gzip). LZMA and gzip are the only algorithms the SPL FIT loader can decompress. The default is none.

Just to check — do we need a user-facing choice for this? The existing FIT_UBOOT_COMP in rockchip-u-boot.dtsi picks the algorithm from whichever of SPL_GZIP / SPL_LZMA is enabled, with no extra Kconfig. The same pattern would work here and would avoid adding a choice that every SPL_FIT board sees in menuconfig, when only Rockchip uses fit,compress today. What do you think?

Quoted 8 lines

boot/Kconfig | 32 ++++++++++++++++++++++++++++++++

 1 file changed, 32 insertions(+)

boot/Kconfig config SPL_FIT_FULL_CHECK · line 244

Quoted 9 lines
boot/Kconfig +9 -0
@@ -236,6 +236,38 @@ config SPL_FIT_FULL_CHECK
+choice
+	prompt "Compression of the FDT in the FIT"
+	depends on SPL_FIT
+	default SPL_FIT_FDT_COMP_NONE
+	help
+	  Select how binman compresses the devicetrees in the FIT. This is
+	  independent of the compression of U-Boot itself. SPL must be able to
+	  decompress the chosen algorithm. Only boards whose binman description
+	  uses the fit,compress property are affected.

If the choice is kept, please tighten the dependency to 'depends on SPL_FIT && (SPL_LZMA || SPL_GZIP)'. Otherwise every SPL_FIT board gets a one-option choice offering only None, which is just menuconfig noise.

boot/Kconfig config SPL_FIT_FULL_CHECK · line 236

Quoted 3 lines
boot/Kconfig +1 -0
@@ -236,6 +236,38 @@ config SPL_FIT_FULL_CHECK
+	prompt "Compression of the FDT in the FIT"

The symbols are SPL_FIT_FDT_COMP_* but the prompt doesn't mention SPL. Something like "SPL FIT: FDT compression" would make it clearer in menuconfig that this is SPL-only.

Regards,
Simon

#14 lore raw

PATCH v2 6/6 rockchip: Allow compression of the FDT in the FIT

In reply to Petr Hodina

Compressing the FDT shrinks the FIT at the cost of decompression time in SPL.

Define FIT_FDT_COMP from the SPL_FIT_FDT_COMP choice and use it in the @fdt-SEQ template via 'fit,compress'.

This has no effect on any current board as no in-tree Rockchip defconfig selects a compression.

---
 arch/arm/dts/rockchip-u-boot.dtsi | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
arch/arm/dts/rockchip-u-boot.dtsi +14 -1
index 4ba6a87e78a..3cb571ddddb 100644
@@ -19,6 +19,19 @@
 #define FIT_UBOOT_COMP		"none"
 #endif
 
+/*
+ * The compression of the FDT is chosen by the SPL_FIT_FDT_COMP choice. It
+ * is independent of FIT_UBOOT_COMP so U-Boot may be gzip-compressed while the
+ * FDT is LZMA-compressed.
+ */
+#if defined(CONFIG_SPL_FIT_FDT_COMP_LZMA)
+#define FIT_FDT_COMP		"lzma"
+#elif defined(CONFIG_SPL_FIT_FDT_COMP_GZIP)
+#define FIT_FDT_COMP		"gzip"
+#else
+#define FIT_FDT_COMP		"none"
+#endif
+
 /*
  * SHA256 should be enabled in SPL when signature validation is involved,
  * CRC32 should only be used for basic checksum validation of FIT images.
@@ -136,7 +149,7 @@
 
 			@fdt-SEQ {
 				description = "fdt-NAME";
-				compression = "none";
+				fit,compress = FIT_FDT_COMP;
 				type = "flat_dt";
 #ifdef FIT_HASH_ALGO
 				hash {
Signature · 1 line
2.55.0
Reviewed-by on v2 6/6
#15 lore raw

Re: [PATCH v2 6/6] rockchip: Allow compression of the FDT in the FIT

Quoted 8 lines · On 2026-10-17T07:38:59, Petr Hodina via B4 Relay…

rockchip: Allow compression of the FDT in the FIT

Compressing the FDT shrinks the FIT at the cost of decompression time in SPL.

Define FIT_FDT_COMP from the SPL_FIT_FDT_COMP choice and use it in the @fdt-SEQ template via 'fit,compress'.

Quoted 7 lines

This has no effect on any current board as no in-tree Rockchip defconfig selects a compression.

arch/arm/dts/rockchip-u-boot.dtsi | 15 ++++++++++++++-

 1 file changed, 14 insertions(+), 1 deletion(-)
#16 lore raw

Re: [PATCH v2 6/6] rockchip: Allow compression of the FDT in the FIT

In reply to Petr Hodina

Hi Petr,

Quoted 26 lines · On 10/17/26 9:39 AM, Petr Hodina via B4 Relay wrote:

From: Petr Hodina <[email protected]>

Compressing the FDT shrinks the FIT at the cost of decompression time in SPL.

Define FIT_FDT_COMP from the SPL_FIT_FDT_COMP choice and use it in the @fdt-SEQ template via 'fit,compress'.

This has no effect on any current board as no in-tree Rockchip defconfig selects a compression.

---
  arch/arm/dts/rockchip-u-boot.dtsi | 15 ++++++++++++++-
  1 file changed, 14 insertions(+), 1 deletion(-)
arch/arm/dts/rockchip-u-boot.dtsi +2 -0
index 4ba6a87e78a..3cb571ddddb 100644
@@ -19,6 +19,19 @@
  #define FIT_UBOOT_COMP		"none"
  #endif
 
+/*
+ * The compression of the FDT is chosen by the SPL_FIT_FDT_COMP choice. It

arch/arm/dts/rockchip-u-boot.dtsi line 33

Quoted 10 lines
arch/arm/dts/rockchip-u-boot.dtsi +10 -0
+ * is independent of FIT_UBOOT_COMP so U-Boot may be gzip-compressed while the
+ * FDT is LZMA-compressed.
+ */
+#if defined(CONFIG_SPL_FIT_FDT_COMP_LZMA)
+#define FIT_FDT_COMP		"lzma"
+#elif defined(CONFIG_SPL_FIT_FDT_COMP_GZIP)
+#define FIT_FDT_COMP		"gzip"
+#else
+#define FIT_FDT_COMP		"none"
+#endif

issue: wrong place for this

We would then need everybody to reimplement that if they want to use it.

Instead, create an invisible string Kconfig symbol which defaults to the string value related to the selected CONFIG_SPL_FIT_FDT_COMP_* in the Kconfig choice menu.

Otherwise, I generally have the same question as Alexey, is there actual size and/or speed improvements you saw on Rockchip for this series?

Cheers,
Quentin

#17 lore raw
In reply to Petr Hodina

Hi Petr,

Quoted 4 lines · On Sat, Oct 17, 2026 at 11:39 AM Petr Hodina via B4 Relay…

Entry_fit's @fdt-SEQ generator always embeds the raw .dtb. Add a 'fit,compress' property so binman can compress it with any algorithm FIT defines (xz is rejected) and set 'compression' to match.

We currently use 'compress' (without the "fit," prefix) for the U-Boot binary. Having multiple spellings for a semantically similar property sounds confusing.

Quoted 2 lines

Add a generic SPL_FIT_FDT_COMP choice (none, LZMA, gzip: what the SPL FIT loader can currently decompress) and use it on Rockchip.

Do you happen to have any numbers regarding the size savings and the real-world cost in loading time? DTBs are not that large, so I'm wondering if it's really worth the added complexity.

Best regards,
Alexey

#18 lore raw

Hi Alexey,

Quoted 3 lines · Alexey Charkov

We currently use 'compress' (without the "fit," prefix) for the U-Boot binary. Having multiple spellings for a semantically similar property sounds confusing.

The 'fit,' prefix is the established convention in Entry_fit for properties that control FIT generation (fit,fdt-list, fit,operation, fit,align, fit,sign, fit,encrypt, fit,engine, ...). The plain 'compress' property acts on an entry's own data at the binman level and pairs with uncomp-size tracking, whereas here we are telling the FIT generator to compress the embedded fdt subimage and emit a matching 'compression' property in the FIT itself. So the two really are different operations and keeping the 'fit,' prefix fits the surrounding code. I think that is the right call.

Regards,
Simon