diff mbox series

[v5] kernel-fit-image: allow extending compatible string property for DTBs

Message ID 20251011094815.950261-1-kavinaya@qti.qualcomm.com
State New
Headers show
Series [v5] kernel-fit-image: allow extending compatible string property for DTBs | expand

Commit Message

Kavinaya S Oct. 11, 2025, 9:48 a.m. UTC
The Linux kernel allows multiple DTBs to share the same compatible string.
For example:
qcs6490-rb3gen2.dtb
qcs6490-rb3gen2-vision-mezzanine.dtb
qcs6490-rb3gen2-industrial-mezzanine.dtb

All of these use the same base compatible string:
compatible = "qcom,qcs6490-rb3gen2", "qcom,qcm6490";

Since the latter two DTBs are overlays on top of the base DTB and do not
modify platform properties, they retain the same compatible string.

When these DTBs are bundled into a single fitImage, the bootloader cannot
distinguish between them due to identical compatible strings.

To address this, introduce a mechanism to extend the compatible string
using a OE build variable:
FIT_DTB_COMPATIBLE_EXTENTION[dtb_name] = "extension"

This appends the extension to the first compatible string in the DTB,
resulting in unique entries in the generated .its file. For example:
FIT_DTB_COMPATIBLE_EXTENTION[qcs6490-rb3gen2-vision-mezzanine] = "vision"
FIT_DTB_COMPATIBLE_EXTENTION[qcs6490-rb3gen2-industrial-mezzanine] = "industrial"

Generates:
compatible = "qcom,qcs6490-rb3gen2-vision", "qcom,qcm6490";
compatible = "qcom,qcs6490-rb3gen2-industrial", "qcom,qcm6490";

Suggested-By: Alexander Kanavin <alex.kanavin@gmail.com>
Suggested-By: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Kavinaya S <kavinaya@qti.qualcomm.com>
---
 meta/classes-recipe/kernel-fit-image.bbclass |  8 ++-
 meta/conf/image-fitimage.conf                | 12 +++++
 meta/lib/oe/fitimage.py                      |  4 +-
 meta/lib/oeqa/selftest/cases/fitimage.py     | 52 ++++++++++++++++++++
 4 files changed, 74 insertions(+), 2 deletions(-)

Comments

Alexander Kanavin Oct. 11, 2025, 5:32 p.m. UTC | #1
Just wanted to say this looks fine to me on a (very) quick read, so if
Dmitry and people on the patch review call have no objections, neither
do I. It needs to pass the autobuilder testing too, you will hear if
something goes wrong.

Alex

On Sat, 11 Oct 2025 at 11:48, Kavinaya S <kavinaya@qti.qualcomm.com> wrote:
>
> The Linux kernel allows multiple DTBs to share the same compatible string.
> For example:
> qcs6490-rb3gen2.dtb
> qcs6490-rb3gen2-vision-mezzanine.dtb
> qcs6490-rb3gen2-industrial-mezzanine.dtb
>
> All of these use the same base compatible string:
> compatible = "qcom,qcs6490-rb3gen2", "qcom,qcm6490";
>
> Since the latter two DTBs are overlays on top of the base DTB and do not
> modify platform properties, they retain the same compatible string.
>
> When these DTBs are bundled into a single fitImage, the bootloader cannot
> distinguish between them due to identical compatible strings.
>
> To address this, introduce a mechanism to extend the compatible string
> using a OE build variable:
> FIT_DTB_COMPATIBLE_EXTENTION[dtb_name] = "extension"
>
> This appends the extension to the first compatible string in the DTB,
> resulting in unique entries in the generated .its file. For example:
> FIT_DTB_COMPATIBLE_EXTENTION[qcs6490-rb3gen2-vision-mezzanine] = "vision"
> FIT_DTB_COMPATIBLE_EXTENTION[qcs6490-rb3gen2-industrial-mezzanine] = "industrial"
>
> Generates:
> compatible = "qcom,qcs6490-rb3gen2-vision", "qcom,qcm6490";
> compatible = "qcom,qcs6490-rb3gen2-industrial", "qcom,qcm6490";
>
> Suggested-By: Alexander Kanavin <alex.kanavin@gmail.com>
> Suggested-By: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> Signed-off-by: Kavinaya S <kavinaya@qti.qualcomm.com>
> ---
>  meta/classes-recipe/kernel-fit-image.bbclass |  8 ++-
>  meta/conf/image-fitimage.conf                | 12 +++++
>  meta/lib/oe/fitimage.py                      |  4 +-
>  meta/lib/oeqa/selftest/cases/fitimage.py     | 52 ++++++++++++++++++++
>  4 files changed, 74 insertions(+), 2 deletions(-)
>
> diff --git a/meta/classes-recipe/kernel-fit-image.bbclass b/meta/classes-recipe/kernel-fit-image.bbclass
> index f04aee1807..7850d565fc 100644
> --- a/meta/classes-recipe/kernel-fit-image.bbclass
> +++ b/meta/classes-recipe/kernel-fit-image.bbclass
> @@ -84,8 +84,14 @@ python do_compile() {
>
>              # Copy the dtb or dtbo file into the FIT image assembly directory
>              shutil.copyfile(os.path.join(kernel_deploydir, dtb_name), dtb_name)
> +
> +            # Consider compatible extention if avilable
> +            name, ext = os.path.splitext(dtb_name)
> +            extention = (d.getVarFlag("FIT_DTB_COMPATIBLE_EXTENTION", name) or "").strip()
> +
>              root_node.fitimage_emit_section_dtb(dtb_name, dtb_name,
> -                d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"))
> +                d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"),
> +                compatible_extention=extention)
>
>      if external_kernel_devicetree:
>          # iterate over all .dtb and .dtbo files in the external kernel devicetree directory
> diff --git a/meta/conf/image-fitimage.conf b/meta/conf/image-fitimage.conf
> index 090ee148f4..86948b6bf3 100644
> --- a/meta/conf/image-fitimage.conf
> +++ b/meta/conf/image-fitimage.conf
> @@ -65,3 +65,15 @@ FIT_ADDRESS_CELLS ?= "1"
>  # Machine configurations needing such a script file should include it in the
>  # SRC_URI of the kernel recipe and set the FIT_UBOOT_ENV parameter.
>  FIT_UBOOT_ENV ?= ""
> +
> +# For specific DTBs extend "compatible" strings when creating FIT images.
> +# Format:
> +#   FIT_DTB_COMPATIBLE_EXTENTION[<dtb_name>] = "<extension>"
> +#
> +# Result:
> +#   dtb_name.dtb {
> +#    ...
> +#    compatible = "string1-extension", "string2", ...;
> +#   };
> +#
> +FIT_DTB_COMPATIBLE_EXTENTION ?= ""
> diff --git a/meta/lib/oe/fitimage.py b/meta/lib/oe/fitimage.py
> index f303799155..98af4aad14 100644
> --- a/meta/lib/oe/fitimage.py
> +++ b/meta/lib/oe/fitimage.py
> @@ -289,7 +289,7 @@ class ItsNodeRootKernel(ItsNode):
>          self._kernel = kernel_node
>
>      def fitimage_emit_section_dtb(self, dtb_id, dtb_path, dtb_loadaddress=None,
> -                                  dtbo_loadaddress=None, add_compatible=False):
> +                                  dtbo_loadaddress=None, add_compatible=False, compatible_extention=""):
>          """Emit the fitImage ITS DTB section"""
>          load=None
>          dtb_ext = os.path.splitext(dtb_path)[1]
> @@ -310,6 +310,8 @@ class ItsNodeRootKernel(ItsNode):
>          compatible = None
>          if add_compatible:
>              compatible = get_compatible_from_dtb(dtb_path)
> +            if compatible and compatible_extention:
> +                compatible[0] = compatible[0] + "-" + compatible_extention
>
>          dtb_node = self.its_add_node_dtb(
>              "fdt-" + dtb_id,
> diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py
> index 195b9ee8b5..dfe34ccdec 100644
> --- a/meta/lib/oeqa/selftest/cases/fitimage.py
> +++ b/meta/lib/oeqa/selftest/cases/fitimage.py
> @@ -17,6 +17,9 @@ from oeqa.selftest.case import OESelftestTestCase
>  from oeqa.utils.commands import runCmd, bitbake, get_bb_vars, get_bb_var
>
>
> +from pathlib import Path
> +
> +
>  class BbVarsMockGenKeys:
>      def __init__(self, keydir, gen_keys="0", sign_enabled="0", keyname="", sign_ind="0", img_keyname=""):
>          self.bb_vars = {
> @@ -819,6 +822,55 @@ MACHINE:forcevariable = "beaglebone-yocto"
>          # The alias is a symlink, therefore the compatible string is equal
>          self.assertEqual(comp_alias, comp)
>
> +    def test_fitimage_compatible_extn_in_its(self):
> +        """
> +        Verify that FIT_DTB_COMPATIBLE_EXTENTION[...] is honored in the generated .its.
> +
> +        This test:
> +        1) Selects beaglebone-yocto machine and a DTB that is part of its kernel.
> +        2) Sets FIT_DTB_COMPATIBLE_EXTENTION[am335x-bonegreen-ext] to custom extension.
> +        3) Runs do_assemble_fitimage to generate the FIT .its.
> +        4) Asserts the .its 'compatible = ...' includes extended ones.
> +
> +        """
> +
> +        kernel_dtb = "am335x-bonegreen-ext.dtb"
> +        dtb_name = os.path.splitext(os.path.basename(kernel_dtb))[0]
> +
> +        config = f"""
> +DISTRO = "poky"
> +MACHINE = "beaglebone-yocto"
> +
> +# Ensure the FIT flow is active
> +KERNEL_CLASSES += "kernel-fit-extra-artifacts "
> +
> +# Ensure the selected DTB is built into the kernel deploy output
> +KERNEL_DEVICETREE = "{kernel_dtb}"
> +
> +# Provide the extension as a varflag (pairs: base:suffix)
> +# Original compatibles: "ti,am335x-bone-green", "ti,am335x-bone-black"
> +FIT_DTB_COMPATIBLE_EXTENTION[{dtb_name}] = "subtypeA"
> +
> +"""
> +        self.write_config(config)
> +
> +        bitbake('virtual/kernel:do_deploy')
> +        bitbake('linux-yocto-fitimage:do_deploy')
> +
> +        # Find the generated .its in DEPLOY_DIR_IMAGE
> +        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
> +        self.assertTrue(deploy_dir_image and os.path.isdir(deploy_dir_image),
> +                    f"DEPLOY_DIR_IMAGE not found or invalid: {deploy_dir_image}")
> +
> +        its_path = os.path.join(deploy_dir_image, 'fit-image.its')
> +        self.assertTrue(os.path.exists(its_path), f"Expected ITS file not found: {its_path}")
> +
> +        # Read the ITS content
> +        its_text = Path(its_path).read_text(encoding='utf-8', errors='ignore')
> +
> +        # Assertions: extended compatibles must appear
> +        self.assertIn('ti,am335x-bone-green-subtypeA', its_text)
> +
>      def test_fit_image_ext_dtb_dtbo(self):
>          """
>          Summary:     Check if FIT image and Image Tree Source (its) are created correctly.
Gyorgy Sarvari Oct. 11, 2025, 7:03 p.m. UTC | #2
On 10/11/25 11:48, Kavinaya S via lists.openembedded.org wrote:
> The Linux kernel allows multiple DTBs to share the same compatible string.
> For example:
> qcs6490-rb3gen2.dtb
> qcs6490-rb3gen2-vision-mezzanine.dtb
> qcs6490-rb3gen2-industrial-mezzanine.dtb
>
> All of these use the same base compatible string:
> compatible = "qcom,qcs6490-rb3gen2", "qcom,qcm6490";
>
> Since the latter two DTBs are overlays on top of the base DTB and do not
> modify platform properties, they retain the same compatible string.
>
> When these DTBs are bundled into a single fitImage, the bootloader cannot
> distinguish between them due to identical compatible strings.
>
> To address this, introduce a mechanism to extend the compatible string
> using a OE build variable:
> FIT_DTB_COMPATIBLE_EXTENTION[dtb_name] = "extension"

One small note: "extension" is misspelled as "extention" multiple times
in the patch.

> This appends the extension to the first compatible string in the DTB,
> resulting in unique entries in the generated .its file. For example:
> FIT_DTB_COMPATIBLE_EXTENTION[qcs6490-rb3gen2-vision-mezzanine] = "vision"
> FIT_DTB_COMPATIBLE_EXTENTION[qcs6490-rb3gen2-industrial-mezzanine] = "industrial"
>
> Generates:
> compatible = "qcom,qcs6490-rb3gen2-vision", "qcom,qcm6490";
> compatible = "qcom,qcs6490-rb3gen2-industrial", "qcom,qcm6490";
>
> Suggested-By: Alexander Kanavin <alex.kanavin@gmail.com>
> Suggested-By: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> Signed-off-by: Kavinaya S <kavinaya@qti.qualcomm.com>
> ---
>  meta/classes-recipe/kernel-fit-image.bbclass |  8 ++-
>  meta/conf/image-fitimage.conf                | 12 +++++
>  meta/lib/oe/fitimage.py                      |  4 +-
>  meta/lib/oeqa/selftest/cases/fitimage.py     | 52 ++++++++++++++++++++
>  4 files changed, 74 insertions(+), 2 deletions(-)
>
> diff --git a/meta/classes-recipe/kernel-fit-image.bbclass b/meta/classes-recipe/kernel-fit-image.bbclass
> index f04aee1807..7850d565fc 100644
> --- a/meta/classes-recipe/kernel-fit-image.bbclass
> +++ b/meta/classes-recipe/kernel-fit-image.bbclass
> @@ -84,8 +84,14 @@ python do_compile() {
>  
>              # Copy the dtb or dtbo file into the FIT image assembly directory
>              shutil.copyfile(os.path.join(kernel_deploydir, dtb_name), dtb_name)
> +
> +            # Consider compatible extention if avilable
> +            name, ext = os.path.splitext(dtb_name)
> +            extention = (d.getVarFlag("FIT_DTB_COMPATIBLE_EXTENTION", name) or "").strip()
> +
>              root_node.fitimage_emit_section_dtb(dtb_name, dtb_name,
> -                d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"))
> +                d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"),
> +                compatible_extention=extention)
>  
>      if external_kernel_devicetree:
>          # iterate over all .dtb and .dtbo files in the external kernel devicetree directory
> diff --git a/meta/conf/image-fitimage.conf b/meta/conf/image-fitimage.conf
> index 090ee148f4..86948b6bf3 100644
> --- a/meta/conf/image-fitimage.conf
> +++ b/meta/conf/image-fitimage.conf
> @@ -65,3 +65,15 @@ FIT_ADDRESS_CELLS ?= "1"
>  # Machine configurations needing such a script file should include it in the
>  # SRC_URI of the kernel recipe and set the FIT_UBOOT_ENV parameter.
>  FIT_UBOOT_ENV ?= ""
> +
> +# For specific DTBs extend "compatible" strings when creating FIT images.
> +# Format:
> +#   FIT_DTB_COMPATIBLE_EXTENTION[<dtb_name>] = "<extension>"
> +#
> +# Result:
> +#   dtb_name.dtb {
> +#    ...
> +#    compatible = "string1-extension", "string2", ...;
> +#   };
> +#
> +FIT_DTB_COMPATIBLE_EXTENTION ?= ""
> diff --git a/meta/lib/oe/fitimage.py b/meta/lib/oe/fitimage.py
> index f303799155..98af4aad14 100644
> --- a/meta/lib/oe/fitimage.py
> +++ b/meta/lib/oe/fitimage.py
> @@ -289,7 +289,7 @@ class ItsNodeRootKernel(ItsNode):
>          self._kernel = kernel_node
>  
>      def fitimage_emit_section_dtb(self, dtb_id, dtb_path, dtb_loadaddress=None,
> -                                  dtbo_loadaddress=None, add_compatible=False):
> +                                  dtbo_loadaddress=None, add_compatible=False, compatible_extention=""):
>          """Emit the fitImage ITS DTB section"""
>          load=None
>          dtb_ext = os.path.splitext(dtb_path)[1]
> @@ -310,6 +310,8 @@ class ItsNodeRootKernel(ItsNode):
>          compatible = None
>          if add_compatible:
>              compatible = get_compatible_from_dtb(dtb_path)
> +            if compatible and compatible_extention:
> +                compatible[0] = compatible[0] + "-" + compatible_extention
>  
>          dtb_node = self.its_add_node_dtb(
>              "fdt-" + dtb_id,
> diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py
> index 195b9ee8b5..dfe34ccdec 100644
> --- a/meta/lib/oeqa/selftest/cases/fitimage.py
> +++ b/meta/lib/oeqa/selftest/cases/fitimage.py
> @@ -17,6 +17,9 @@ from oeqa.selftest.case import OESelftestTestCase
>  from oeqa.utils.commands import runCmd, bitbake, get_bb_vars, get_bb_var
>  
>  
> +from pathlib import Path
> +
> +
>  class BbVarsMockGenKeys:
>      def __init__(self, keydir, gen_keys="0", sign_enabled="0", keyname="", sign_ind="0", img_keyname=""):
>          self.bb_vars = {
> @@ -819,6 +822,55 @@ MACHINE:forcevariable = "beaglebone-yocto"
>          # The alias is a symlink, therefore the compatible string is equal
>          self.assertEqual(comp_alias, comp)
>  
> +    def test_fitimage_compatible_extn_in_its(self):
> +        """
> +        Verify that FIT_DTB_COMPATIBLE_EXTENTION[...] is honored in the generated .its.
> +
> +        This test:
> +        1) Selects beaglebone-yocto machine and a DTB that is part of its kernel.
> +        2) Sets FIT_DTB_COMPATIBLE_EXTENTION[am335x-bonegreen-ext] to custom extension.
> +        3) Runs do_assemble_fitimage to generate the FIT .its.
> +        4) Asserts the .its 'compatible = ...' includes extended ones.
> +
> +        """
> +
> +        kernel_dtb = "am335x-bonegreen-ext.dtb"
> +        dtb_name = os.path.splitext(os.path.basename(kernel_dtb))[0]
> +
> +        config = f"""
> +DISTRO = "poky"
> +MACHINE = "beaglebone-yocto"
> +
> +# Ensure the FIT flow is active
> +KERNEL_CLASSES += "kernel-fit-extra-artifacts "
> +
> +# Ensure the selected DTB is built into the kernel deploy output
> +KERNEL_DEVICETREE = "{kernel_dtb}"
> +
> +# Provide the extension as a varflag (pairs: base:suffix)
> +# Original compatibles: "ti,am335x-bone-green", "ti,am335x-bone-black"
> +FIT_DTB_COMPATIBLE_EXTENTION[{dtb_name}] = "subtypeA"
> +
> +"""
> +        self.write_config(config)
> +
> +        bitbake('virtual/kernel:do_deploy')
> +        bitbake('linux-yocto-fitimage:do_deploy')
> +
> +        # Find the generated .its in DEPLOY_DIR_IMAGE
> +        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
> +        self.assertTrue(deploy_dir_image and os.path.isdir(deploy_dir_image),
> +                    f"DEPLOY_DIR_IMAGE not found or invalid: {deploy_dir_image}")
> +
> +        its_path = os.path.join(deploy_dir_image, 'fit-image.its')
> +        self.assertTrue(os.path.exists(its_path), f"Expected ITS file not found: {its_path}")
> +
> +        # Read the ITS content
> +        its_text = Path(its_path).read_text(encoding='utf-8', errors='ignore')
> +
> +        # Assertions: extended compatibles must appear
> +        self.assertIn('ti,am335x-bone-green-subtypeA', its_text)
> +
>      def test_fit_image_ext_dtb_dtbo(self):
>          """
>          Summary:     Check if FIT image and Image Tree Source (its) are created correctly.
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#224714): https://lists.openembedded.org/g/openembedded-core/message/224714
> Mute This Topic: https://lists.openembedded.org/mt/115702434/6084445
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [skandigraun@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
Dmitry Baryshkov Oct. 11, 2025, 8:07 p.m. UTC | #3
On Sat, Oct 11, 2025 at 03:18:15PM +0530, Kavinaya S wrote:
> The Linux kernel allows multiple DTBs to share the same compatible string.
> For example:
> qcs6490-rb3gen2.dtb
> qcs6490-rb3gen2-vision-mezzanine.dtb
> qcs6490-rb3gen2-industrial-mezzanine.dtb
> 
> All of these use the same base compatible string:
> compatible = "qcom,qcs6490-rb3gen2", "qcom,qcm6490";
> 
> Since the latter two DTBs are overlays on top of the base DTB and do not
> modify platform properties, they retain the same compatible string.
> 
> When these DTBs are bundled into a single fitImage, the bootloader cannot
> distinguish between them due to identical compatible strings.
> 
> To address this, introduce a mechanism to extend the compatible string
> using a OE build variable:
> FIT_DTB_COMPATIBLE_EXTENTION[dtb_name] = "extension"
> 

[...]

> +FIT_DTB_COMPATIBLE_EXTENTION ?= ""
> diff --git a/meta/lib/oe/fitimage.py b/meta/lib/oe/fitimage.py
> index f303799155..98af4aad14 100644
> --- a/meta/lib/oe/fitimage.py
> +++ b/meta/lib/oe/fitimage.py
> @@ -289,7 +289,7 @@ class ItsNodeRootKernel(ItsNode):
>          self._kernel = kernel_node
>  
>      def fitimage_emit_section_dtb(self, dtb_id, dtb_path, dtb_loadaddress=None,
> -                                  dtbo_loadaddress=None, add_compatible=False):
> +                                  dtbo_loadaddress=None, add_compatible=False, compatible_extention=""):

I don't think this completely fulfills our needs. We have a usecase,
where we want to supply a complete compatible string (in order to build
the DTB fitImage. It would be much nicer to be able to specify the whole
compatible string here rather than just specifying an extension (and
still having to hack the function later).

>          """Emit the fitImage ITS DTB section"""
>          load=None
>          dtb_ext = os.path.splitext(dtb_path)[1]
Kavinaya S Oct. 12, 2025, 4:18 a.m. UTC | #4
Hi Dmitry,

If other reviewers agree I have no concern with replacement of complete compatible string.

Thanks,
Kavinaya
Mathieu Dubois-Briand Oct. 12, 2025, 7:58 a.m. UTC | #5
On Sat Oct 11, 2025 at 11:48 AM CEST, Kavinaya S via lists.openembedded.org wrote:
> The Linux kernel allows multiple DTBs to share the same compatible string.
> For example:
> qcs6490-rb3gen2.dtb
> qcs6490-rb3gen2-vision-mezzanine.dtb
> qcs6490-rb3gen2-industrial-mezzanine.dtb
>
> All of these use the same base compatible string:
> compatible = "qcom,qcs6490-rb3gen2", "qcom,qcm6490";
>
> Since the latter two DTBs are overlays on top of the base DTB and do not
> modify platform properties, they retain the same compatible string.
>
> When these DTBs are bundled into a single fitImage, the bootloader cannot
> distinguish between them due to identical compatible strings.
>
> To address this, introduce a mechanism to extend the compatible string
> using a OE build variable:
> FIT_DTB_COMPATIBLE_EXTENTION[dtb_name] = "extension"
>
> This appends the extension to the first compatible string in the DTB,
> resulting in unique entries in the generated .its file. For example:
> FIT_DTB_COMPATIBLE_EXTENTION[qcs6490-rb3gen2-vision-mezzanine] = "vision"
> FIT_DTB_COMPATIBLE_EXTENTION[qcs6490-rb3gen2-industrial-mezzanine] = "industrial"
>
> Generates:
> compatible = "qcom,qcs6490-rb3gen2-vision", "qcom,qcm6490";
> compatible = "qcom,qcs6490-rb3gen2-industrial", "qcom,qcm6490";
>
> Suggested-By: Alexander Kanavin <alex.kanavin@gmail.com>
> Suggested-By: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> Signed-off-by: Kavinaya S <kavinaya@qti.qualcomm.com>
> ---

Hi Kavinaya,

Thanks for the new version.

It looks like this is breaking some selftest:

AssertionError: 'ti,am335x-bone-green-subtypeA' not found in '/dts-v1/;\n\n/ {\n        description = "Kernel fitImage for Poky (Yocto Project Reference Distro)/1.0/beaglebone-yocto";\n        #address-cells = <1>;\n        images {\n                kernel-1 {\n                        description = "Linux kernel";\n                        type = "kernel";\n                        compression = "none";\n                        data = /incbin/("linux.bin");\n                        arch = "arm";\n                        os = "linux";\n                        load = <0x20008000>;\n                        entry = <0x20008000>;\n                        hash-1 {\n                                algo = "sha256";\n                        };\n                };\n                fdt-am335x-bone.dtb {\n                        description = "Flattened Device Tree blob";\n                        type = "flat_dt";\n                        compression = "none";\n                        data = /incbin/("am335x-bone.dtb");\n                        arch = "arm";\n                        hash-1 {\n                                algo = "sha256";\n                        };\n                };\n                fdt-am335x-boneblack.dtb {\n                        description = "Flattened Device Tree blob";\n                        type = "flat_dt";\n                        compression = "none";\n                        data = /incbin/("am335x-boneblack.dtb");\n                        arch = "arm";\n                        hash-1 {\n                                algo = "sha256";\n                        };\n                };\n                fdt-am335x-bonegreen.dtb {\n                        description = "Flattened Device Tree blob";\n                        type = "flat_dt";\n                        compression = "none";\n                        data = /incbin/("am335x-bonegreen.dtb");\n                        arch = "arm";\n                        hash-1 {\n                                algo = "sha256";\n                        };\n                };\n        };\n        configurations {\n                default = "conf-am335x-bone.dtb";\n                conf-am335x-bone.dtb {\n                        description = "1 Linux kernel, FDT blob";\n                        kernel = "kernel-1";\n                        fdt = "fdt-am335x-bone.dtb";\n                        hash-1 {\n                                algo = "sha256";\n                        };\n                };\n                conf-am335x-boneblack.dtb {\n                        description = "0 Linux kernel, FDT blob";\n                        kernel = "kernel-1";\n                        fdt = "fdt-am335x-boneblack.dtb";\n                        hash-1 {\n                                algo = "sha256";\n                        };\n                };\n                conf-am335x-bonegreen.dtb {\n                        description = "0 Linux kernel, FDT blob";\n                        kernel = "kernel-1";\n                        fdt = "fdt-am335x-bonegreen.dtb";\n                        hash-1 {\n                                algo = "sha256";\n                        };\n                };\n        };\n};\n'
...
2025-10-11 15:18:18,764 - oe-selftest - INFO - fitimage.KernelFitImageRecipeTests.test_fitimage_compatible_extn_in_its (subunit.RemotedTestCase)
2025-10-11 15:18:18,771 - oe-selftest - INFO -  ... FAIL

Can you have a look at this failure, please?

Thanks,
Mathieu
Kavinaya S Oct. 12, 2025, 9:45 a.m. UTC | #6
Hi Mathieu,

Sure. I will update the test case and post it in the new patch (v5.1).

Thanks,
Kavinaya
Dmitry Baryshkov Oct. 12, 2025, 3:06 p.m. UTC | #7
On Sat, Oct 11, 2025 at 09:18:02PM -0700, Kavinaya S wrote:
> Hi Dmitry,
> 
> If other reviewers agree I have no concern with replacement of complete compatible string.

Please don't trim the contents. What are you replying to? How would one
know it?

Anyway, what is the plan to handle our DTB fitImages?
Kavinaya S Oct. 12, 2025, 4:17 p.m. UTC | #8
On Sun, Oct 12, 2025 at 08:37 PM, Dmitry Baryshkov wrote:

>
> On Sat, Oct 11, 2025 at 09:18:02PM -0700, Kavinaya S wrote:
> 
> > 
> > Hi Dmitry,
> > 
> > If other reviewers agree I have no concern with replacement of complete
> > compatible string.
> 
> Please don't trim the contents. What are you replying to? How would one
> know it?
> 
> Anyway, what is the plan to handle our DTB fitImages?
> 
> --
> With best wishes
> Dmitry
>
Hi Dmitry,

For Qualcomm DTBs extending the compatible string would be sufficient as the format planned is 
compatible = "qcom,<SoC>[-<soc_version>][-<foundry_id>]-<board>[/<subtype>][-<pmic>][-<board_version>]"
 
In this "qcom,<SoC>" would be from base Kernel device tree and remaining part to be added via extension. 
If others also agree to replace the entire compatible sting, then entire string can be updated in the format we like. 
Either case the Qualcomm DTB fitImages have a path forward. 

Thanks,
Kavinaya
diff mbox series

Patch

diff --git a/meta/classes-recipe/kernel-fit-image.bbclass b/meta/classes-recipe/kernel-fit-image.bbclass
index f04aee1807..7850d565fc 100644
--- a/meta/classes-recipe/kernel-fit-image.bbclass
+++ b/meta/classes-recipe/kernel-fit-image.bbclass
@@ -84,8 +84,14 @@  python do_compile() {
 
             # Copy the dtb or dtbo file into the FIT image assembly directory
             shutil.copyfile(os.path.join(kernel_deploydir, dtb_name), dtb_name)
+
+            # Consider compatible extention if avilable
+            name, ext = os.path.splitext(dtb_name)
+            extention = (d.getVarFlag("FIT_DTB_COMPATIBLE_EXTENTION", name) or "").strip()
+
             root_node.fitimage_emit_section_dtb(dtb_name, dtb_name,
-                d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"))
+                d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"),
+                compatible_extention=extention)
 
     if external_kernel_devicetree:
         # iterate over all .dtb and .dtbo files in the external kernel devicetree directory
diff --git a/meta/conf/image-fitimage.conf b/meta/conf/image-fitimage.conf
index 090ee148f4..86948b6bf3 100644
--- a/meta/conf/image-fitimage.conf
+++ b/meta/conf/image-fitimage.conf
@@ -65,3 +65,15 @@  FIT_ADDRESS_CELLS ?= "1"
 # Machine configurations needing such a script file should include it in the
 # SRC_URI of the kernel recipe and set the FIT_UBOOT_ENV parameter.
 FIT_UBOOT_ENV ?= ""
+
+# For specific DTBs extend "compatible" strings when creating FIT images.
+# Format:
+#   FIT_DTB_COMPATIBLE_EXTENTION[<dtb_name>] = "<extension>"
+#
+# Result:
+#   dtb_name.dtb {
+#    ...
+#    compatible = "string1-extension", "string2", ...;
+#   };
+#
+FIT_DTB_COMPATIBLE_EXTENTION ?= ""
diff --git a/meta/lib/oe/fitimage.py b/meta/lib/oe/fitimage.py
index f303799155..98af4aad14 100644
--- a/meta/lib/oe/fitimage.py
+++ b/meta/lib/oe/fitimage.py
@@ -289,7 +289,7 @@  class ItsNodeRootKernel(ItsNode):
         self._kernel = kernel_node
 
     def fitimage_emit_section_dtb(self, dtb_id, dtb_path, dtb_loadaddress=None,
-                                  dtbo_loadaddress=None, add_compatible=False):
+                                  dtbo_loadaddress=None, add_compatible=False, compatible_extention=""):
         """Emit the fitImage ITS DTB section"""
         load=None
         dtb_ext = os.path.splitext(dtb_path)[1]
@@ -310,6 +310,8 @@  class ItsNodeRootKernel(ItsNode):
         compatible = None
         if add_compatible:
             compatible = get_compatible_from_dtb(dtb_path)
+            if compatible and compatible_extention:
+                compatible[0] = compatible[0] + "-" + compatible_extention
 
         dtb_node = self.its_add_node_dtb(
             "fdt-" + dtb_id,
diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py
index 195b9ee8b5..dfe34ccdec 100644
--- a/meta/lib/oeqa/selftest/cases/fitimage.py
+++ b/meta/lib/oeqa/selftest/cases/fitimage.py
@@ -17,6 +17,9 @@  from oeqa.selftest.case import OESelftestTestCase
 from oeqa.utils.commands import runCmd, bitbake, get_bb_vars, get_bb_var
 
 
+from pathlib import Path
+
+
 class BbVarsMockGenKeys:
     def __init__(self, keydir, gen_keys="0", sign_enabled="0", keyname="", sign_ind="0", img_keyname=""):
         self.bb_vars = {
@@ -819,6 +822,55 @@  MACHINE:forcevariable = "beaglebone-yocto"
         # The alias is a symlink, therefore the compatible string is equal
         self.assertEqual(comp_alias, comp)
 
+    def test_fitimage_compatible_extn_in_its(self):
+        """
+        Verify that FIT_DTB_COMPATIBLE_EXTENTION[...] is honored in the generated .its.
+
+        This test:
+        1) Selects beaglebone-yocto machine and a DTB that is part of its kernel.
+        2) Sets FIT_DTB_COMPATIBLE_EXTENTION[am335x-bonegreen-ext] to custom extension.
+        3) Runs do_assemble_fitimage to generate the FIT .its.
+        4) Asserts the .its 'compatible = ...' includes extended ones.
+
+        """
+
+        kernel_dtb = "am335x-bonegreen-ext.dtb"
+        dtb_name = os.path.splitext(os.path.basename(kernel_dtb))[0]
+
+        config = f"""
+DISTRO = "poky"
+MACHINE = "beaglebone-yocto"
+
+# Ensure the FIT flow is active
+KERNEL_CLASSES += "kernel-fit-extra-artifacts "
+
+# Ensure the selected DTB is built into the kernel deploy output
+KERNEL_DEVICETREE = "{kernel_dtb}"
+
+# Provide the extension as a varflag (pairs: base:suffix)
+# Original compatibles: "ti,am335x-bone-green", "ti,am335x-bone-black"
+FIT_DTB_COMPATIBLE_EXTENTION[{dtb_name}] = "subtypeA"
+
+"""
+        self.write_config(config)
+
+        bitbake('virtual/kernel:do_deploy')
+        bitbake('linux-yocto-fitimage:do_deploy')
+
+        # Find the generated .its in DEPLOY_DIR_IMAGE
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        self.assertTrue(deploy_dir_image and os.path.isdir(deploy_dir_image),
+                    f"DEPLOY_DIR_IMAGE not found or invalid: {deploy_dir_image}")
+
+        its_path = os.path.join(deploy_dir_image, 'fit-image.its')
+        self.assertTrue(os.path.exists(its_path), f"Expected ITS file not found: {its_path}")
+
+        # Read the ITS content
+        its_text = Path(its_path).read_text(encoding='utf-8', errors='ignore')
+
+        # Assertions: extended compatibles must appear
+        self.assertIn('ti,am335x-bone-green-subtypeA', its_text)
+
     def test_fit_image_ext_dtb_dtbo(self):
         """
         Summary:     Check if FIT image and Image Tree Source (its) are created correctly.