binman: btool: Add Xilinx Bootgen btool

Add the Xilinx Bootgen as bintool. Xilinx Bootgen is used to create
bootable SPL (FSBL in Xilinx terms) images for Zynq/ZynqMP devices. The
btool creates a signed version of the SPL. Additionally to signing the
key source for the decryption engine can be passend to the boot image.

Signed-off-by: Lukas Funke <lukas.funke@weidmueller.com>
diff --git a/tools/binman/bintools.rst b/tools/binman/bintools.rst
index 20ee243..1336f4d 100644
--- a/tools/binman/bintools.rst
+++ b/tools/binman/bintools.rst
@@ -208,7 +208,7 @@
 
 
 Bintool: bootgen: Sign ZynqMP FSBL image
----------------------------------------------
+----------------------------------------
 
 This bintool supports running `bootgen` in order to sign a SPL for ZynqMP
 devices.
diff --git a/tools/binman/btool/bootgen.py b/tools/binman/btool/bootgen.py
new file mode 100644
index 0000000..f2ca552
--- /dev/null
+++ b/tools/binman/btool/bootgen.py
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (C) 2023 Weidmüller Interface GmbH & Co. KG
+# Lukas Funke <lukas.funke@weidmueller.com>
+#
+"""Bintool implementation for bootgen
+
+bootgen allows creating bootable SPL for Zynq(MP)
+
+Documentation is available via:
+https://www.xilinx.com/support/documents/sw_manuals/xilinx2022_1/ug1283-bootgen-user-guide.pdf
+
+Source code is available at:
+https://github.com/Xilinx/bootgen
+
+"""
+
+from binman import bintool
+from u_boot_pylib import tools
+
+# pylint: disable=C0103
+class Bintoolbootgen(bintool.Bintool):
+    """Generate bootable fsbl image for zynq/zynqmp
+
+    This bintools supports running Xilinx "bootgen" in order
+    to generate a bootable, authenticated image form an SPL.
+
+    """
+    def __init__(self, name):
+        super().__init__(name, 'Xilinx Bootgen',
+                         version_regex=r'^\*\*\*\*\*\* *Xilinx Bootgen *(.*)',
+                         version_args='-help')
+
+    # pylint: disable=R0913
+    def sign(self, arch, spl_elf_fname, pmufw_elf_fname,
+             psk_fname, ssk_fname, fsbl_config, auth_params, keysrc_enc,
+             output_fname):
+        """Sign SPL elf file and bundle it with PMU firmware into an image
+
+        The method bundels the SPL together with a 'Platform Management Unit'
+        (PMU)[1] firmware into a single bootable image. The image in turn is
+        signed with the provided 'secondary secret key' (ssk), which in turn is
+        signed with the 'primary secret key' (psk). In order to verify the
+        authenticity of the ppk, it's hash has to be fused into the device
+        itself.
+
+        In Xilinx terms the SPL is usually called 'FSBL'
+        (First Stage Boot Loader). The jobs of the SPL and the FSBL are mostly
+        the same: load bitstream, bootstrap u-boot.
+
+        Args:
+            arch (str): Xilinx SoC architecture. Currently only 'zynqmp' is
+                supported.
+            spl_elf_fname (str): Filename of SPL ELF file. The filename must end
+                with '.elf' in order for bootgen to recognized it as an ELF
+                file. Otherwise the start address field is missinterpreted.
+            pmufw_elf_fname (str): Filename PMU ELF firmware.
+            psk_fname (str): Filename of the primary secret key (psk). The psk
+                is a .pem file which holds the RSA private key used for signing
+                the secondary secret key.
+            ssk_fname (str): Filename of the secondary secret key. The ssk
+                is a .pem file which holds the RSA private key used for signing
+                the actual boot firmware.
+            fsbl_config (str): FSBL config options. A string list of fsbl config
+                options. Valid values according to [2] are:
+                "bh_auth_enable": Boot Header Authentication Enable: RSA
+                    authentication of the bootimage is done
+                    excluding the verification of PPK hash and SPK ID. This is
+                    useful for debugging before bricking a device.
+                "auth_only": Boot image is only RSA signed. FSBL should not be
+                    decrypted. See the
+                    Zynq UltraScale+ Device Technical Reference Manual (UG1085)
+                    for more information.
+                There are more options which relate to PUF (physical unclonable
+                functions). Please refer to Xilinx manuals for further info.
+            auth_params (str): Authentication parameter. A semicolon separated
+                list of authentication parameters. Valid values according to [3]
+                are:
+                "ppk_select=<0|1>" - Select which ppk to use
+                "spk_id=<32-bit spk id>" - Specifies which SPK can be
+                    used or revoked, default is 0x0
+                "spk_select=<spk-efuse/user-efuse>" - To differentiate spk and
+                    user efuses.
+                "auth_header" - To authenticate headers when no partition
+                    is authenticated.
+            keysrc_enc (str): This specifies the Key source for encryption.
+                Valid values according to [3] are:
+                "bbram_red_key" - RED key stored in BBRAM
+                "efuse_red_key" - RED key stored in eFUSE
+                "efuse_gry_key" - Grey (Obfuscated) Key stored in eFUSE.
+                "bh_gry_key" - Grey (Obfuscated) Key stored in boot header
+                "bh_blk_key" - Black Key stored in boot header
+                "efuse_blk_key" - Black Key stored in eFUSE
+                "kup_key" - User Key
+
+            output_fname (str): Filename where bootgen should write the result
+        
+        Returns:
+            str: Bootgen output from stdout
+
+        [1] https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841724/PMU+Firmware
+        [2] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/fsbl_config
+        [3] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/auth_params
+        [4] https://docs.xilinx.com/r/en-US/ug1283-bootgen-user-guide/keysrc_encryption
+        """
+
+        _fsbl_config = f"[fsbl_config] {fsbl_config}" if fsbl_config else ""
+        _auth_params = f"[auth_params] {auth_params}" if auth_params else ""
+        _keysrc_enc  = f"[keysrc_encryption] {keysrc_enc}" if keysrc_enc else ""
+
+        bif_template = f"""u_boot_spl_aes_rsa: {{
+            [pskfile] {psk_fname}
+            [sskfile] {ssk_fname}
+            {_keysrc_enc}
+            {_fsbl_config}
+            {_auth_params}
+            [ bootloader,
+              authentication = rsa,
+              destination_cpu=a53-0] {spl_elf_fname}
+            [pmufw_image] {pmufw_elf_fname}
+        }}"""
+        args = ["-arch", arch]
+
+        bif_fname = tools.get_output_filename('bootgen-in.sign.bif')
+        tools.write_file(bif_fname, bif_template, False)
+        args += ["-image", bif_fname, '-w', '-o', output_fname]
+        return self.run_cmd(*args)
+
+    def fetch(self, method):
+        """Fetch bootgen from git"""
+        if method != bintool.FETCH_BUILD:
+            return None
+
+        result = self.build_from_git(
+            'https://github.com/Xilinx/bootgen',
+            'all',
+            'bootgen')
+        return result