public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms
@ 2026-04-17 12:09 Aswin Murugan
  2026-04-17 12:09 ` [PATCH v3 1/7] mach-snapdragon: Add generic SMEM cache infrastructure Aswin Murugan
                   ` (8 more replies)
  0 siblings, 9 replies; 17+ messages in thread
From: Aswin Murugan @ 2026-04-17 12:09 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

This series adds dynamic device tree selection from FIT images for
Qualcomm Snapdragon platforms, enabling U-Boot to select the
appropriate DTB based on hardware parameters detected from SMEM.

Qualcomm fit based DTB format is documented in [1]
The fit image contains only DTB, while the kernel will be part of UKI image.

The implementation consists of three parts:

1. SMEM cache infrastructure: Provides cached access to commonly
   used SMEM data (socinfo, RAM partitions) to avoid redundant
   lookups during boot. Includes socinfo header from Linux kernel
   for SoC identification.

2. FIT multi-DTB selection: Implements the core selection logic
   that reads hardware parameters from SMEM, parses metadata DTB,
   matches FIT configurations, and loads the selected DTB with
   overlays. Integrates with EFI boot flow by setting fdt_addr.

3. mkimage: add fatfs image type for FAT partition images
   Added fatimage.c handler that uses mkfs.vfat and mcopy to create
   FAT images from a directory.

[1] https://github.com/qualcomm-linux/qcom-dtb-metadata/blob/main/Documentation.md

---
Changes in v3:
1. Runtime IMEM address lookup via DT: Removed CONFIG_QCOM_IMEM_SIZE Kconfig option.
   Added qcom_imem_table[] mapping SoC compatible strings to IMEM addresses.

2. Split SoC version sources: SoC hardware version now read from TCSR register via
   qcom_read_tcsr_soc_version(). The soc_info->plat_ver from SMEM is stored separately
   as board_version. Added socver and boardrev metadata node matching for finer-grained DTB selection.

3. qcom_load_fit_image() returns int: Changed return type from efi_status_t to int,
   returning standard Linux error codes for consistency with the rest of the driver.

4. Code cleanup: strtok() replaced with strsep(); memcpy + manual null-termination replaced with strlcpy();
   DDR thresholds use SZ_* macros; compatible matching and FDT loading extracted into dedicated helpers.

5. image: add IH_TYPE_FATFS image type: Added new fatfs image type to represent a raw FAT
   filesystem partition image, registered in the image type lookup table.

6. mkimage: add fatfs image type for FAT partition images: Added fatimage.c handler that
   uses mkfs.vfat and mcopy to create FAT images from a directory.
   New --fat-extra-space, --fat-type, --fat-volume-id, --fat-mkfs-opts long options added
   to mkimage.

7. doc: document mkimage fatfs type and Qualcomm multi-DTB: Updated 'doc/mkimage.1' for the new
   fatfs type and options. Added 'doc/board/qualcomm/multi_dtb.rst' covering FIT ITS configuration,
   QCOM metadata format, socver/boardrev guidelines, and image creation steps.

Link to v2:
https://lore.kernel.org/u-boot/20260129184817.224101-1-aswin.murugan@oss.qualcomm.com/

Changes in v2:
- In v1, a combined DTB format was used for multi-DTB support. Based on
  feedback, v2 implements FIT-based DTB selection instead.
- Link to v1: https://lore.kernel.org/all/20260106122134.2047864-1-aswin.murugan@oss.qualcomm.com/

Aswin Murugan (7):
  mach-snapdragon: Add generic SMEM cache infrastructure
  mach-snapdragon: Add FIT multi-DTB selection support
  configs: snapdragon: Enable FIT multi-DTB and configure IMEM
  image: add IH_TYPE_FATFS image type
  mkimage: add fatfs image type for FAT partition images
  doc: document mkimage fatfs type and Qualcomm multi-DTB
  mach-snapdragon: Reorder header includes

 arch/arm/mach-snapdragon/Kconfig             |    8 +
 arch/arm/mach-snapdragon/Makefile            |    1 +
 arch/arm/mach-snapdragon/board.c             |  123 +-
 arch/arm/mach-snapdragon/qcom-priv.h         |   24 +
 arch/arm/mach-snapdragon/qcom_fit_multidtb.c | 1103 ++++++++++++++++++
 arch/arm/mach-snapdragon/qcom_fit_multidtb.h |  189 +++
 arch/arm/mach-snapdragon/rampart.h           |  225 ++++
 boot/image.c                                 |    1 +
 configs/qcom_defconfig                       |    2 +
 doc/board/qualcomm/index.rst                 |    1 +
 doc/board/qualcomm/multi_dtb.rst             |  352 ++++++
 doc/mkimage.1                                |  103 ++
 include/image.h                              |    1 +
 include/soc/qcom/socinfo.h                   |  114 ++
 tools/Makefile                               |    1 +
 tools/fatimage.c                             |  495 ++++++++
 tools/fatimage.h                             |   25 +
 tools/mkimage.c                              |   21 +
 tools/mkimage.h                              |   15 +
 19 files changed, 2793 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm/mach-snapdragon/qcom_fit_multidtb.c
 create mode 100644 arch/arm/mach-snapdragon/qcom_fit_multidtb.h
 create mode 100644 arch/arm/mach-snapdragon/rampart.h
 create mode 100644 doc/board/qualcomm/multi_dtb.rst
 create mode 100644 include/soc/qcom/socinfo.h
 create mode 100644 tools/fatimage.c
 create mode 100644 tools/fatimage.h

-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v3 1/7] mach-snapdragon: Add generic SMEM cache infrastructure
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
@ 2026-04-17 12:09 ` Aswin Murugan
  2026-04-20  4:06   ` Simon Glass
  2026-04-17 12:09 ` [PATCH v3 2/7] mach-snapdragon: Add FIT multi-DTB selection support Aswin Murugan
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Aswin Murugan @ 2026-04-17 12:09 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Add cached access functions for commonly used SMEM data to reduce
redundant SMEM lookups across the boot process.

This patch introduces three generic caching functions:
- qcom_get_smem_device(): Cached SMEM device access
- qcom_get_socinfo(): Cached socinfo structure access
- qcom_get_ram_partitions(): Cached RAM partition table access

The implementation includes new header files for data structures:
- include/soc/qcom/socinfo.h: Added socinfo header from Linux [1]
  Provides socinfo structure definitions for SoC identification
  and hardware parameters
- arch/arm/mach-snapdragon/rampart.h: Provides RAM partition table
  structures for memory layout information

The caching mechanism initializes SMEM data on first access and
returns cached pointers on subsequent calls, avoiding expensive
SMEM lookups during boot. This infrastructure is designed to be
reusable by other Qualcomm-specific features that require hardware
information from SMEM.

The functions provide a clean API for accessing:
- SoC information (chip ID, version, platform details)
- RAM partition layout for memory size calculations
- Hardware parameters needed for device-specific configurations

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/soc/qcom/socinfo.h?id=7dcc1dfaa3d1cd3aafed2beb7086ed34fdb22303

Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
---
Changes in v3:
1. Addressed the review comments
---
 arch/arm/mach-snapdragon/board.c     |  95 +++++++++++
 arch/arm/mach-snapdragon/qcom-priv.h |  24 +++
 arch/arm/mach-snapdragon/rampart.h   | 225 +++++++++++++++++++++++++++
 include/soc/qcom/socinfo.h           | 114 ++++++++++++++
 4 files changed, 458 insertions(+)
 create mode 100644 arch/arm/mach-snapdragon/rampart.h
 create mode 100644 include/soc/qcom/socinfo.h

diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
index 5fb3240acc5..6edb61b5b36 100644
--- a/arch/arm/mach-snapdragon/board.c
+++ b/arch/arm/mach-snapdragon/board.c
@@ -16,6 +16,7 @@
 #include <asm/system.h>
 #include <dm/device.h>
 #include <dm/pinctrl.h>
+#include <dm/uclass.h>
 #include <dm/uclass-internal.h>
 #include <dm/read.h>
 #include <power/regulator.h>
@@ -30,6 +31,7 @@
 #include <malloc.h>
 #include <fdt_support.h>
 #include <usb.h>
+#include <smem.h>
 #include <sort.h>
 #include <time.h>
 
@@ -39,6 +41,16 @@ DECLARE_GLOBAL_DATA_PTR;
 
 enum qcom_boot_source qcom_boot_source __section(".data") = 0;
 
+/**
+ * struct smem_cache - Cached SMEM device and data pointers
+ * @soc_info: Pointer to the SoC info structure
+ * @ram_part: Pointer to the RAM partition table
+ */
+static struct {
+	struct socinfo *soc_info;
+	struct usable_ram_partition_table *ram_part;
+} smem_cache;
+
 static struct mm_region rbx_mem_map[CONFIG_NR_DRAM_BANKS + 2] = { { 0 } };
 
 struct mm_region *mem_map = rbx_mem_map;
@@ -749,3 +761,86 @@ void enable_caches(void)
 	}
 	dcache_enable();
 }
+
+/**
+ * qcom_get_smem_device() - Get cached SMEM device
+ *
+ * This function provides cached access to the SMEM device.
+ * On first call, it initializes the SMEM device.
+ * Subsequent calls return the cached pointer.
+ *
+ * Return: Pointer to SMEM device on success, NULL on failure
+ */
+struct udevice *qcom_get_smem_device(void)
+{
+	struct udevice *dev;
+
+	if (uclass_first_device_err(UCLASS_SMEM, &dev)) {
+		log_err("Failed to get SMEM device\n");
+		return NULL;
+	}
+
+	return dev;
+}
+
+/**
+ * qcom_get_socinfo() - Get cached socinfo from SMEM
+ *
+ * This function provides cached access to the socinfo structure from SMEM.
+ * On first call, it initializes the SMEM device and retrieves the socinfo.
+ * Subsequent calls return the cached pointer.
+ *
+ * Return: Pointer to socinfo structure on success, NULL on failure
+ */
+struct socinfo *qcom_get_socinfo(void)
+{
+	size_t size;
+	struct udevice *dev;
+
+	if (smem_cache.soc_info)
+		return smem_cache.soc_info;
+
+	dev = qcom_get_smem_device();
+	if (!dev)
+		return NULL;
+
+	smem_cache.soc_info = smem_get(dev, 0, SMEM_HW_SW_BUILD_ID, &size);
+	if (!smem_cache.soc_info) {
+		log_err("Failed to get socinfo from SMEM\n");
+		return NULL;
+	}
+
+	return smem_cache.soc_info;
+}
+
+/**
+ * qcom_get_ram_partitions() - Get cached RAM partition table from SMEM
+ *
+ * This function provides cached access to the RAM partition table from SMEM.
+ * On first call, it retrieves the partition table from SMEM.
+ * Subsequent calls return the cached pointer.
+ *
+ * Return: Pointer to RAM partition table on success, NULL on failure
+ */
+struct usable_ram_partition_table *qcom_get_ram_partitions(void)
+{
+	size_t size;
+	struct udevice *dev;
+
+	if (smem_cache.ram_part)
+		return smem_cache.ram_part;
+
+	dev = qcom_get_smem_device();
+	if (!dev)
+		return NULL;
+
+	smem_cache.ram_part = smem_get(dev, 0,
+				       SMEM_USABLE_RAM_PARTITION_TABLE,
+				       &size);
+	if (!smem_cache.ram_part) {
+		log_err("Failed to get RAM partition table from SMEM\n");
+		return NULL;
+	}
+
+	return smem_cache.ram_part;
+}
diff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h
index b8bf574e8bb..ae426c9512d 100644
--- a/arch/arm/mach-snapdragon/qcom-priv.h
+++ b/arch/arm/mach-snapdragon/qcom-priv.h
@@ -3,6 +3,9 @@
 #ifndef __QCOM_PRIV_H__
 #define __QCOM_PRIV_H__
 
+#include <soc/qcom/socinfo.h>
+#include "rampart.h"
+
 /**
  * enum qcom_boot_source - Track where we got loaded from.
  * Used for capsule update logic.
@@ -17,6 +20,27 @@ enum qcom_boot_source {
 
 extern enum qcom_boot_source qcom_boot_source;
 
+/**
+ * qcom_get_smem_device() - Get cached SMEM device
+ *
+ * Return: Pointer to SMEM device on success, NULL on failure
+ */
+struct udevice *qcom_get_smem_device(void);
+
+/**
+ * qcom_get_socinfo() - Get cached socinfo from SMEM
+ *
+ * Return: Pointer to socinfo structure on success, NULL on failure
+ */
+struct socinfo *qcom_get_socinfo(void);
+
+/**
+ * qcom_get_ram_partitions() - Get cached RAM partition table from SMEM
+ *
+ * Return: Pointer to RAM partition table on success, NULL on failure
+ */
+struct usable_ram_partition_table *qcom_get_ram_partitions(void);
+
 #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)
 void qcom_configure_capsule_updates(void);
 #else
diff --git a/arch/arm/mach-snapdragon/rampart.h b/arch/arm/mach-snapdragon/rampart.h
new file mode 100644
index 00000000000..b6f056af2d0
--- /dev/null
+++ b/arch/arm/mach-snapdragon/rampart.h
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RAM partition table definitions
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ */
+
+#define SMEM_USABLE_RAM_PARTITION_TABLE		402
+
+#define RAM_PARTITION_H_MAJOR  03
+#define RAM_PARTITION_H_MINOR  00
+
+
+/**
+ * Total length of zero filled name string. This is not a C
+ * string, as it can occupy the total number of bytes, and if
+ * it does, it does not require a zero terminator. It cannot
+ * be manipulated with standard string handling library functions.
+ */
+#define RAM_PART_NAME_LENGTH 16
+
+/**
+ * Number of RAM partition entries which are usable by APPS.
+ */
+#define RAM_NUM_PART_ENTRIES 32
+
+/**
+ * @name: Magic numbers
+ * Used in identifying valid RAM partition table.
+ */
+#define RAM_PART_MAGIC1     0x9da5e0a8
+#define RAM_PART_MAGIC2     0xaf9ec4e2
+
+/**
+ * Must increment this version number whenever RAM structure of
+ * RAM partition table changes.
+ */
+#define RAM_PARTITION_VERSION   0x3
+
+/*
+ * Value which indicates the partition can grow to fill the
+ * rest of RAM. Must only be used on the last partition.
+ */
+#define RAM_PARTITION_GROW  0xffffffff
+
+/**
+ * RAM partition API return types.
+ */
+enum  ram_partition_return_type {
+	RAM_PART_SUCCESS = 0,             /* Successful return from API */
+	RAM_PART_NULL_PTR_ERR,            /* Partition table/entry null pointer */
+	RAM_PART_OUT_OF_BOUND_PTR_ERR,    /* Partition table pointer is not in SMEM */
+	RAM_PART_TABLE_EMPTY_ERR,         /* Trying to delete entry from empty table */
+	RAM_PART_TABLE_FULL_ERR,          /* Trying to add entry to full table */
+	RAM_PART_CATEGORY_NOT_EXIST_ERR,  /* Partition doesn't belong to any memory category */
+	RAM_PART_OTHER_ERR,               /* Unknown error */
+	RAM_PART_RETURN_MAX_SIZE = 0x7fffffff
+};
+
+/**
+ * RAM partition attributes.
+ */
+enum ram_partition_attribute_t {
+	RAM_PARTITION_DEFAULT_ATTRB = ~0,  /* No specific attribute definition */
+	RAM_PARTITION_READ_ONLY = 0,       /* Read-only RAM partition */
+	RAM_PARTITION_READWRITE,           /* Read/write RAM partition */
+	RAM_PARTITION_ATTRIBUTE_MAX_SIZE = 0x7fffffff
+};
+
+/**
+ * RAM partition categories.
+ */
+enum ram_partition_category_t {
+	RAM_PARTITION_DEFAULT_CATEGORY = ~0,  /* No specific category definition */
+	RAM_PARTITION_IRAM = 4,                   /* IRAM RAM partition */
+	RAM_PARTITION_IMEM = 5,                   /* IMEM RAM partition */
+	RAM_PARTITION_SDRAM = 14,                  /* SDRAM type without specific bus information**/
+	RAM_PARTITION_CATEGORY_MAX_SIZE = 0x7fffffff
+};
+
+/**
+ * RAM Partition domains.
+ * @note: For shared RAM partition, domain value would be 0b11:\n
+ * RAM_PARTITION_APPS_DOMAIN | RAM_PARTITION_MODEM_DOMAIN.
+ */
+enum ram_partition_domain_t {
+	RAM_PARTITION_DEFAULT_DOMAIN = 0,  /* 0b00: No specific domain definition */
+	RAM_PARTITION_APPS_DOMAIN = 1,     /* 0b01: APPS RAM partition */
+	RAM_PARTITION_MODEM_DOMAIN = 2,    /* 0b10: MODEM RAM partition */
+	RAM_PARTITION_DOMAIN_MAX_SIZE = 0x7fffffff
+};
+
+/**
+ * RAM Partition types.
+ * @note: The RAM_PARTITION_SYS_MEMORY type represents DDR rams that are attached
+ * to the current system.
+ */
+enum ram_partition_type_t {
+	RAM_PARTITION_SYS_MEMORY = 1,        /* system memory */
+	RAM_PARTITION_BOOT_REGION_MEMORY1,   /* boot loader memory 1 */
+	RAM_PARTITION_BOOT_REGION_MEMORY2,   /* boot loader memory 2, reserved */
+	RAM_PARTITION_APPSBL_MEMORY,         /* apps boot loader memory */
+	RAM_PARTITION_APPS_MEMORY,           /* apps usage memory */
+	RAM_PARTITION_TOOLS_FV_MEMORY,       /* tools usage memory */
+	RAM_PARTITION_QUANTUM_FV_MEMORY,     /* quantum usage memory */
+	RAM_PARTITION_QUEST_FV_MEMORY,       /* quest usage memory */
+	RAM_PARTITION_TYPE_MAX_SIZE = 0x7fffffff
+};
+
+/* Holds information for an entry in the RAM partition table */
+struct ram_partition_entry {
+	char name[RAM_PART_NAME_LENGTH];  /* Partition name, unused for now */
+	u64 start_address;                /* Partition start address in RAM */
+	u64 length;                       /* Partition length in RAM in Bytes */
+	u32 partition_attribute;          /* Partition attribute */
+	u32 partition_category;           /* Partition category */
+	u32 partition_domain;             /* Partition domain */
+	u32 partition_type;               /* Partition type */
+	u32 num_partitions;               /* Number of partitions on device */
+	u32 hw_info;                      /* hw information such as type and frequency */
+	u8 highest_bank_bit;              /* Highest bit corresponding to a bank */
+	u8 reserve0;                      /* Reserved for future use */
+	u8 reserve1;                      /* Reserved for future use */
+	u8 reserve2;                      /* Reserved for future use */
+	u32 min_pasr_size;                /* Minimum PASR size in MB */
+	u64 available_length;             /* Available Partition length in RAM in Bytes */
+};
+
+/*
+ * Defines the RAM partition table structure
+ *
+ * Do not change the placement of the first four elements so that future
+ * compatibility will always be guaranteed at least for the identifiers.
+ *
+ * The other portion of the structure may be changed as necessary to accommodate
+ * new features. Be sure to increment version number if you change it.
+ */
+struct usable_ram_partition_table {
+	u32 magic1;          /* Magic number to identify valid RAM partition table */
+	u32 magic2;          /* Magic number to identify valid RAM partition table */
+	u32 version;         /* Version number to track structure definition changes */
+	u32 reserved1;       /* Reserved for future use */
+
+	u32 num_partitions;  /* Number of RAM partition table entries */
+
+	u32 reserved2;       /* Added for 8 bytes alignment of header */
+
+	/* RAM partition table entries */
+	struct ram_partition_entry ram_part_entry[RAM_NUM_PART_ENTRIES];
+};
+
+/* Version 1 structure 32 Bit - Holds information for an entry in the RAM partition table */
+struct ram_partition_entry_v1 {
+	char name[RAM_PART_NAME_LENGTH];  /* Partition name, unused for now */
+	u64 start_address;                /* Partition start address in RAM */
+	u64 length;                       /* Partition length in RAM in Bytes */
+	u32 partition_attribute;          /* Partition attribute */
+	u32 partition_category;           /* Partition category */
+	u32 partition_domain;             /* Partition domain */
+	u32 partition_type;               /* Partition type */
+	u32 num_partitions;               /* Number of partitions on device */
+	u32 hw_info;                      /* hw information such as type and frequency */
+	u32 reserved4;                    /* Reserved for future use */
+	u32 reserved5;                    /* Reserved for future use */
+};
+
+/*
+ * Defines the RAM partition table structure (Version 1)
+ *
+ * Do not change the placement of the first four elements so that future
+ * compatibility will always be guaranteed at least for the identifiers.
+ *
+ * The other portion of the structure may be changed as necessary to accommodate
+ * new features. Be sure to increment version number if you change it.
+ */
+struct usable_ram_partition_table_v1 {
+	u32 magic1;          /* Magic number to identify valid RAM partition table */
+	u32 magic2;          /* Magic number to identify valid RAM partition table */
+	u32 version;         /* Version number to track structure definition changes */
+	u32 reserved1;       /* Reserved for future use */
+
+	u32 num_partitions;  /* Number of RAM partition table entries */
+
+	u32 reserved2;       /* Added for 8 bytes alignment of header */
+
+	/* RAM partition table entries */
+	struct ram_partition_entry_v1 ram_part_entry_v1[RAM_NUM_PART_ENTRIES];
+};
+
+/* Version 0 structure 32 Bit - Holds information for an entry in the RAM partition table */
+struct ram_partition_entry_v0 {
+	char name[RAM_PART_NAME_LENGTH];  /* Partition name, unused for now */
+	u32 start_address;                /* Partition start address in RAM */
+	u32 length;                       /* Partition length in RAM in Bytes */
+	u32 partition_attribute;          /* Partition attribute */
+	u32 partition_category;           /* Partition category */
+	u32 partition_domain;             /* Partition domain */
+	u32 partition_type;               /* Partition type */
+	u32 num_partitions;               /* Number of partitions on device */
+	u32 reserved3;                    /* Reserved for future use */
+	u32 reserved4;                    /* Reserved for future use */
+	u32 reserved5;                    /* Reserved for future use */
+};
+
+/*
+ * Defines the RAM partition table structure (Version 0)
+ *
+ * Do not change the placement of the first four elements so that future
+ * compatibility will always be guaranteed at least for the identifiers.
+ *
+ * The other portion of the structure may be changed as necessary to accommodate
+ * new features. Be sure to increment version number if you change it.
+ */
+struct usable_ram_partition_table_v0 {
+	u32 magic1;          /* Magic number to identify valid RAM partition table */
+	u32 magic2;          /* Magic number to identify valid RAM partition table */
+	u32 version;         /* Version number to track structure definition changes */
+	u32 reserved1;       /* Reserved for future use */
+
+	u32 num_partitions;  /* Number of RAM partition table entries */
+
+	/* RAM partition table entries */
+	struct ram_partition_entry_v0 ram_part_entry_v0[RAM_NUM_PART_ENTRIES];
+};
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
new file mode 100644
index 00000000000..1bb6e200e1f
--- /dev/null
+++ b/include/soc/qcom/socinfo.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __QCOM_SOCINFO_H__
+#define __QCOM_SOCINFO_H__
+
+#include <linux/types.h>
+
+/*
+ * SMEM item id, used to acquire handles to respective
+ * SMEM region.
+ */
+#define SMEM_HW_SW_BUILD_ID		137
+
+#define SMEM_SOCINFO_BUILD_ID_LENGTH	32
+#define SMEM_SOCINFO_CHIP_ID_LENGTH	32
+
+/*
+ * SoC version type with major number in the upper 16 bits and minor
+ * number in the lower 16 bits.
+ */
+#define SOCINFO_MAJOR(ver) (((ver) >> 16) & 0xffff)
+#define SOCINFO_MINOR(ver) ((ver) & 0xffff)
+#define SOCINFO_VERSION(maj, min)  ((((maj) & 0xffff) << 16) | ((min) & 0xffff))
+
+/* Socinfo SMEM item structure */
+struct socinfo {
+	__le32 fmt;
+	__le32 id;
+	__le32 ver;
+	char build_id[SMEM_SOCINFO_BUILD_ID_LENGTH];
+	/* Version 2 */
+	__le32 raw_id;
+	__le32 raw_ver;
+	/* Version 3 */
+	__le32 hw_plat;
+	/* Version 4 */
+	__le32 plat_ver;
+	/* Version 5 */
+	__le32 accessory_chip;
+	/* Version 6 */
+	__le32 hw_plat_subtype;
+	/* Version 7 */
+	__le32 pmic_model;
+	__le32 pmic_die_rev;
+	/* Version 8 */
+	__le32 pmic_model_1;
+	__le32 pmic_die_rev_1;
+	__le32 pmic_model_2;
+	__le32 pmic_die_rev_2;
+	/* Version 9 */
+	__le32 foundry_id;
+	/* Version 10 */
+	__le32 serial_num;
+	/* Version 11 */
+	__le32 num_pmics;
+	__le32 pmic_array_offset;
+	/* Version 12 */
+	__le32 chip_family;
+	__le32 raw_device_family;
+	__le32 raw_device_num;
+	/* Version 13 */
+	__le32 nproduct_id;
+	char chip_id[SMEM_SOCINFO_CHIP_ID_LENGTH];
+	/* Version 14 */
+	__le32 num_clusters;
+	__le32 ncluster_array_offset;
+	__le32 num_subset_parts;
+	__le32 nsubset_parts_array_offset;
+	/* Version 15 */
+	__le32 nmodem_supported;
+	/* Version 16 */
+	__le32  feature_code;
+	__le32  pcode;
+	__le32  npartnamemap_offset;
+	__le32  nnum_partname_mapping;
+	/* Version 17 */
+	__le32 oem_variant;
+	/* Version 18 */
+	__le32 num_kvps;
+	__le32 kvps_offset;
+	/* Version 19 */
+	__le32 num_func_clusters;
+	__le32 boot_cluster;
+	__le32 boot_core;
+};
+
+/* Internal feature codes */
+enum qcom_socinfo_feature_code {
+	/* External feature codes */
+	SOCINFO_FC_UNKNOWN = 0x0,
+	SOCINFO_FC_AA,
+	SOCINFO_FC_AB,
+	SOCINFO_FC_AC,
+	SOCINFO_FC_AD,
+	SOCINFO_FC_AE,
+	SOCINFO_FC_AF,
+	SOCINFO_FC_AG,
+	SOCINFO_FC_AH,
+};
+
+/* Internal feature codes */
+/* Valid values: 0 <= n <= 0xf */
+#define SOCINFO_FC_Yn(n)		(0xf1 + (n))
+#define SOCINFO_FC_INT_MAX		SOCINFO_FC_Yn(0xf)
+
+/* Product codes */
+#define SOCINFO_PC_UNKNOWN		0
+#define SOCINFO_PCn(n)			((n) + 1)
+#define SOCINFO_PC_RESERVE		(BIT(31) - 1)
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 2/7] mach-snapdragon: Add FIT multi-DTB selection support
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
  2026-04-17 12:09 ` [PATCH v3 1/7] mach-snapdragon: Add generic SMEM cache infrastructure Aswin Murugan
@ 2026-04-17 12:09 ` Aswin Murugan
  2026-04-20  4:06   ` Simon Glass
  2026-04-17 12:09 ` [PATCH v3 3/7] configs: snapdragon: Enable FIT multi-DTB and configure IMEM Aswin Murugan
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Aswin Murugan @ 2026-04-17 12:09 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Implement multi DTB selection from FIT images based on hardware
detection via SMEM.

The implementation provides:

1. Hardware Detection: Reads SoC parameters from SMEM including chip ID,
   version, platform ID, OEM variant, DDR size, and storage type from IMEM.

2. Metadata DTB Processing: Parses a metadata DTB (first image in FIT)
   to build a "bucket list" of hardware-specific node names that match
   the detected hardware parameters.

3. FIT Configuration Matching: Uses standard FIT mechanisms to find the
   configuration with the most matching tokens in its compatible string
   compared to the hardware-derived bucket list.

4. DTB Loading and Overlays: Loads the base DTB and applies any DTBOs
   specified in the selected configuration using standard FIT overlay
   application.

5. EFI Integration: Loads selected dtb from qclinux_fit.img and sets
   fdt_addr for use by the EFI boot flow.

This enables multi DTB selection across hardware variants.

Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
---
Changes in v3:
1. Runtime IMEM address lookup via DT: Removed CONFIG_QCOM_IMEM_SIZE Kconfig option.
   Added qcom_imem_table[] mapping SoC compatible strings to IMEM addresses.

2. Split SoC version sources: SoC hardware version now read from TCSR register via
   qcom_read_tcsr_soc_version(). The soc_info->plat_ver from SMEM is stored separately
   as board_version. Added socver and boardrev metadata node matching for finer-grained DTB selection.

3. qcom_load_fit_image() returns int: Changed return type from efi_status_t to int,
   returning standard Linux error codes for consistency with the rest of the driver.

4. Code cleanup: strtok() replaced with strsep(); memcpy + manual null-termination replaced with strlcpy();
   DDR thresholds use SZ_* macros; compatible matching and FDT loading extracted into dedicated helpers.
---
 arch/arm/mach-snapdragon/Kconfig             |    8 +
 arch/arm/mach-snapdragon/Makefile            |    1 +
 arch/arm/mach-snapdragon/board.c             |    7 +
 arch/arm/mach-snapdragon/qcom_fit_multidtb.c | 1103 ++++++++++++++++++
 arch/arm/mach-snapdragon/qcom_fit_multidtb.h |  189 +++
 5 files changed, 1308 insertions(+)
 create mode 100644 arch/arm/mach-snapdragon/qcom_fit_multidtb.c
 create mode 100644 arch/arm/mach-snapdragon/qcom_fit_multidtb.h

diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig
index d3de8693b5a..0f03672ee6b 100644
--- a/arch/arm/mach-snapdragon/Kconfig
+++ b/arch/arm/mach-snapdragon/Kconfig
@@ -42,4 +42,12 @@ config SYS_CONFIG_NAME
 	  Based on this option include/configs/<CONFIG_SYS_CONFIG_NAME>.h header
 	  will be used for board configuration.
 
+config QCOM_FIT_MULTIDTB
+	bool "Enable FIT multi-DTB selection for Qualcomm platforms"
+	depends on FIT
+	help
+	  Enable FIT multi-DTB selection for Qualcomm platforms.
+	  This allows U-Boot to select the appropriate device tree
+	  from a FIT image.
+
 endif
diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile
index 343e825c6fd..76e285021a1 100644
--- a/arch/arm/mach-snapdragon/Makefile
+++ b/arch/arm/mach-snapdragon/Makefile
@@ -5,3 +5,4 @@
 obj-y += board.o
 obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += capsule_update.o
 obj-$(CONFIG_OF_LIVE) += of_fixup.o
+obj-$(CONFIG_QCOM_FIT_MULTIDTB) += qcom_fit_multidtb.o
diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
index 6edb61b5b36..6a482ed186e 100644
--- a/arch/arm/mach-snapdragon/board.c
+++ b/arch/arm/mach-snapdragon/board.c
@@ -35,6 +35,7 @@
 #include <sort.h>
 #include <time.h>
 
+#include "qcom_fit_multidtb.h"
 #include "qcom-priv.h"
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -585,6 +586,12 @@ int board_late_init(void)
 	/* Configure the dfu_string for capsule updates */
 	qcom_configure_capsule_updates();
 
+	/* Try FIT multi-DTB selection if enabled */
+	if (IS_ENABLED(CONFIG_QCOM_FIT_MULTIDTB)) {
+		if (!qcom_fit_multidtb_setup())
+			log_debug("FIT multi-DTB selection not available or failed\n");
+	}
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.c b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c
new file mode 100644
index 00000000000..7bf4449ea03
--- /dev/null
+++ b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c
@@ -0,0 +1,1103 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm FIT Multi-DTB Selection
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Automatic DTB selection from FIT images based on hardware detection via SMEM.
+ * Loads qclinux_fit.img from dtb partition, detects hardware parameters,
+ * and selects the best matching DTB configuration.
+ */
+
+#include <blk.h>
+#include <dm.h>
+#include <efi_api.h>
+#include <efi_loader.h>
+#include <env.h>
+#include <image.h>
+#include <lmb.h>
+#include <log.h>
+#include <malloc.h>
+#include <part.h>
+#include <smem.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <linux/libfdt.h>
+#include <linux/list.h>
+#include <linux/sizes.h>
+#include <linux/string.h>
+#include <soc/qcom/socinfo.h>
+
+#include "qcom_fit_multidtb.h"
+#include "qcom-priv.h"
+
+#define TCSR_SOC_HW_VERSION        0x01fc8000
+#define TCSR_MAJOR_VERSION_MASK    0x0000ff00
+#define TCSR_MAJOR_VERSION_SHIFT   8
+#define TCSR_MINOR_VERSION_MASK    0x000000ff
+#define TCSR_MINOR_VERSION_SHIFT   0
+
+#define lmb_alloc(size, addr) lmb_alloc_mem(LMB_MEM_ALLOC_ANY, SZ_2M, addr, size, LMB_NONE)
+
+/* Maximum values to match (SOC needs 2) */
+#define MAX_MATCH_VALUES 2
+
+/* Metadata DTB node names */
+#define META_NODE_OEM          "oem"
+#define META_NODE_SOC          "soc"
+#define META_NODE_SOCVER       "socver"
+#define META_NODE_BOARD        "board"
+#define META_NODE_BOARDREV     "boardrev"
+#define META_NODE_SOC_SKU      "soc-sku"
+#define META_NODE_BOARD_SUBTYPE_PERIPHERAL "board-subtype-peripheral-subtype"
+#define META_NODE_BOARD_SUBTYPE_STORAGE    "board-subtype-storage-type"
+#define META_NODE_BOARD_SUBTYPE_DDR_SIZE   "board-subtype-memory-size"
+#define META_NODE_SOFTSKU      "softsku"
+
+/* Property names */
+#define PROP_OEM_ID            "oem-id"
+#define PROP_MSM_ID            "msm-id"
+#define PROP_SOCVER_ID         "socver-id"
+#define PROP_BOARD_ID          "board-id"
+#define PROP_BOARDREV_ID       "boardrev-id"
+#define PROP_BOARD_SUBTYPE     "board-subtype"
+#define PROP_SOFTSKU_ID        "softsku-id"
+#define PROP_COMPATIBLE        "compatible"
+#define PROP_FDT               "fdt"
+#define PROP_DATA              "data"
+
+/**
+ * add_to_bucket() - Add a node name to the bucket list
+ * @name: Node name to add
+ * @name_len: Length of the name
+ * @bucket_head: Head of the bucket list
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int add_to_bucket(const char *name, int name_len, struct list_head *bucket_head)
+{
+	struct bucket_node *node;
+
+	node = malloc(sizeof(*node));
+	if (!node)
+		return -ENOMEM;
+
+	node->name = malloc(name_len + 1);
+	if (!node->name) {
+		free(node);
+		return -ENOMEM;
+	}
+
+	strlcpy(node->name, name, name_len + 1);
+
+	list_add_tail(&node->list, bucket_head);
+
+	return 0;
+}
+
+/**
+ * search_in_bucket() - Check if a name exists in the bucket list
+ * @name: Name to search for
+ * @bucket_head: Head of the bucket list
+ *
+ * Return: true if found, false otherwise
+ */
+static bool search_in_bucket(const char *name, struct list_head *bucket_head)
+{
+	struct bucket_node *node;
+
+	list_for_each_entry(node, bucket_head, list) {
+		if (!strcmp(node->name, name))
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * free_bucket_list() - Free all nodes in the bucket list
+ * @bucket_head: Head of the bucket list
+ */
+static void free_bucket_list(struct list_head *bucket_head)
+{
+	struct bucket_node *node, *tmp;
+
+	list_for_each_entry_safe(node, tmp, bucket_head, list) {
+		list_del(&node->list);
+		free(node->name);
+		free(node);
+	}
+}
+
+/**
+ * qcom_get_ddr_size_type() - Get DDR size type from SMEM RAM partitions
+ * @ddr_type: Pointer to store DDR type
+ *
+ * This function reads RAM partition information from SMEM and calculates
+ * the total DDR size, then maps it to a DDR type constant (0-10).
+ *
+ * Return: 0 on success, negative on failure
+ */
+static int qcom_get_ddr_size_type(u32 *ddr_type)
+{
+	struct usable_ram_partition_table *rpt;
+	struct ram_partition_entry *rpe;
+	u64 total_ddr_size = 0;
+	int part;
+
+	rpt = qcom_get_ram_partitions();
+	if (!rpt) {
+		log_err("Failed to get RAM partition table\n");
+		return -ENOENT;
+	}
+
+	rpe = &rpt->ram_part_entry[0];
+	for (part = 0; part < rpt->num_partitions; part++, rpe++) {
+		if (rpe->partition_category == RAM_PARTITION_SDRAM &&
+		    rpe->partition_type == RAM_PARTITION_SYS_MEMORY) {
+			total_ddr_size += rpe->available_length;
+			log_debug("RAM partition %d: start=0x%llx size=0x%llx\n",
+				  part, rpe->start_address, rpe->available_length);
+		}
+	}
+
+	log_info("Total DDR Size: 0x%llx (%llu MB)\n",
+		 total_ddr_size, total_ddr_size / SZ_1M);
+
+	*ddr_type = 0;
+	if (total_ddr_size <= DDR_128MB)
+		*ddr_type = DDRTYPE_128MB;
+	else if (total_ddr_size <= DDR_256MB)
+		*ddr_type = DDRTYPE_256MB;
+	else if (total_ddr_size <= DDR_512MB)
+		*ddr_type = DDRTYPE_512MB;
+	else if (total_ddr_size <= DDR_1024MB)
+		*ddr_type = DDRTYPE_1024MB;
+	else if (total_ddr_size <= DDR_2048MB)
+		*ddr_type = DDRTYPE_2048MB;
+	else if (total_ddr_size <= DDR_3072MB)
+		*ddr_type = DDRTYPE_3072MB;
+	else if (total_ddr_size <= DDR_4096MB)
+		*ddr_type = DDRTYPE_4096MB;
+
+	log_debug("DDR Type: %u\n", *ddr_type);
+
+	return 0;
+}
+
+/**
+ * qcom_get_imem_address() - Look up shared IMEM cookie address for this SoC
+ *
+ * Reads the root node compatible string from the device tree and searches
+ * the qcom_imem_table for a matching entry.
+ *
+ * Return: Physical address of shared IMEM cookie, or 0 if not found
+ */
+static uintptr_t qcom_get_imem_address(void)
+{
+	const struct qcom_imem_info *entry;
+	const char *soc_compat;
+	int len;
+
+	soc_compat = fdt_getprop(gd->fdt_blob, 0, "compatible", &len);
+	if (!soc_compat) {
+		log_warning("Cannot read SoC compatible from DT\n");
+		return 0;
+	}
+
+	for (entry = qcom_imem_table; entry->compatible; entry++) {
+		if (fdt_stringlist_contains(soc_compat, len, entry->compatible))
+			return entry->shared_imem_addr;
+	}
+
+	log_warning("SoC not found in IMEM table\n");
+	return 0;
+}
+
+/**
+ * qcom_get_storage_type() - Detect storage type (UFS/EMMC/NAND)
+ *
+ * Reads the boot device type from the shared IMEM cookie structure populated
+ * by the bootloader. The shared IMEM address is looked up from a per-SoC
+ * table (qcom_imem_table) using the device tree compatible string.
+ *
+ * Falls back to UFS if the SoC is not in the table or if the IMEM cookie
+ * magic/version validation fails.
+ *
+ * Return: mem_card_type enum value (UFS/EMMC/NAND), or UFS as fallback
+ */
+static enum mem_card_type qcom_get_storage_type(void)
+{
+	struct boot_imem_cookie *imem;
+	uintptr_t shared_imem_addr;
+
+	shared_imem_addr = qcom_get_imem_address();
+	if (!shared_imem_addr) {
+		log_warning("SoC not in IMEM table, defaulting to UFS\n");
+		return UFS;
+	}
+
+	imem = (struct boot_imem_cookie *)shared_imem_addr;
+
+	if (imem->shared_imem_magic != BOOT_SHARED_IMEM_MAGIC_NUM) {
+		log_warning("Invalid shared IMEM magic: 0x%x, defaulting to UFS\n",
+			    imem->shared_imem_magic);
+		return UFS;
+	}
+
+	if (imem->shared_imem_version < BOOT_SHARED_IMEM_VERSION_NUM) {
+		log_warning("Invalid shared IMEM version: %u, defaulting to UFS\n",
+			    imem->shared_imem_version);
+		return UFS;
+	}
+
+	log_info("Shared IMEM: magic=0x%x, version=%u, boot_device_type=%u\n",
+		 imem->shared_imem_magic, imem->shared_imem_version,
+		 imem->boot_device_type);
+
+	switch (imem->boot_device_type) {
+	case UFS_FLASH:
+		return UFS;
+	case MMC_FLASH:
+	case SDC_FLASH:
+		return EMMC;
+	case NAND_FLASH:
+		return NAND;
+	default:
+		log_warning("Unknown shared IMEM boot device: %u, defaulting to UFS\n",
+			    imem->boot_device_type);
+		return UFS;
+	}
+}
+
+static u32 qcom_read_tcsr_soc_version(void)
+{
+	u32 reg_val = readl(TCSR_SOC_HW_VERSION);
+	u32 major = (reg_val & TCSR_MAJOR_VERSION_MASK) >> TCSR_MAJOR_VERSION_SHIFT;
+	u32 minor = (reg_val & TCSR_MINOR_VERSION_MASK) >> TCSR_MINOR_VERSION_SHIFT;
+
+	return (major << 4) | minor;
+}
+
+/**
+ * qcom_detect_hardware_params() - Detect all hardware parameters from SMEM
+ * @params: Pointer to hardware parameters structure
+ *
+ * This function reads hardware information from SMEM and populates the
+ * qcom_hw_params structure with all necessary data for DTB selection.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_detect_hardware_params(struct qcom_hw_params *params)
+{
+	struct socinfo *soc_info;
+	int ret;
+	u32 raw_version;
+
+	memset(params, 0, sizeof(*params));
+
+	soc_info = qcom_get_socinfo();
+	if (!soc_info) {
+		log_err("Failed to get SOC info from SMEM\n");
+		return -ENODEV;
+	}
+
+	params->chip_id = le32_to_cpu(soc_info->id) & 0xffff;
+
+	raw_version = le32_to_cpu(soc_info->plat_ver);
+	params->board_version = (SOCINFO_MAJOR(raw_version) << 4) | SOCINFO_MINOR(raw_version);
+
+	params->chip_version = qcom_read_tcsr_soc_version();
+
+	params->platform = le32_to_cpu(soc_info->hw_plat);
+	params->subtype = le32_to_cpu(soc_info->hw_plat_subtype);
+
+	if (le32_to_cpu(soc_info->fmt) >= 17)
+		params->oem_variant_id = le32_to_cpu(soc_info->oem_variant);
+
+	if (le32_to_cpu(soc_info->fmt) >= 9)
+		params->foundry_id = le32_to_cpu(soc_info->foundry_id);
+
+	ret = qcom_get_ddr_size_type(&params->ddr_size_type);
+	if (ret)
+		log_warning("Failed to get DDR size, defaulting to 0\n");
+
+	params->storage_type = qcom_get_storage_type();
+
+	log_info("Hardware Parameters:\n");
+	log_info("  Chip ID: 0x%x\n", params->chip_id);
+	log_info("  Chip Version: 0x%x\n", params->chip_version);
+	log_info("  Board Version: 0x%x\n", params->board_version);
+	log_info("  Platform: 0x%x\n", params->platform);
+	log_info("  Subtype: 0x%x\n", params->subtype);
+	log_info("  OEM Variant ID: 0x%x\n", params->oem_variant_id);
+	log_info("  DDR Size Type: %u\n", params->ddr_size_type);
+	log_info("  Storage Type: %u\n", params->storage_type);
+	log_info("  Foundry ID: 0x%x\n", params->foundry_id);
+
+	return 0;
+}
+
+/**
+ * log_match_values() - Log matched hardware parameter values
+ * @log_type: Type label for logging (e.g., "SOC", "Board")
+ * @subnode_name: Name of the matched node
+ * @num_match_values: Number of values to log
+ * @match_values: Array of matched values
+ */
+static void log_match_values(const char *log_type, const char *subnode_name,
+			     int num_match_values, const u32 *match_values)
+{
+	int i;
+
+	log_info("Matched %s: %s (", log_type, subnode_name);
+
+	for (i = 0; i < num_match_values; i++) {
+		if (i > 0)
+			log_info(", ");
+		log_info("val%d=0x%x", i + 1, match_values[i]);
+	}
+
+	log_info(")\n");
+}
+
+/**
+ * process_node() - Generic metadata node processor
+ * @type: Type of node to process
+ * @metadata: Metadata DTB pointer
+ * @root_offset: Root node offset
+ * @params: Hardware parameters
+ * @bucket_head: Bucket list head
+ *
+ * Processes different types of nodes in the metadata DTB. Handles matching
+ * hardware parameters against DTB properties, with support for bit masking/shifting
+ * and fallback values.
+ *
+ * Return: 0 on success, -ENOENT if no match, other negative on error
+ */
+static int process_node(enum node_process_type type,
+		       void *metadata,
+		       int root_offset,
+		       struct qcom_hw_params *params,
+		       struct list_head *bucket_head)
+{
+	const char *node_name, *prop_name, *log_type;
+	const char *fallback;
+	const char *subnode_name;
+	int node_offset, subnode, len, name_len;
+	int num_match_values, i;
+	u32 match_values[MAX_MATCH_VALUES];
+	u32 masks[MAX_MATCH_VALUES];
+	int shifts[MAX_MATCH_VALUES];
+	bool all_match;
+
+	fallback = NULL;
+	num_match_values = 1;
+	memset(shifts, 0, sizeof(shifts));
+	memset(masks, 0xff, sizeof(masks));
+
+	switch (type) {
+	case NODE_TYPE_OEM:
+		node_name = META_NODE_OEM;
+		prop_name = PROP_OEM_ID;
+		match_values[0] = params->oem_variant_id;
+		log_type = "OEM";
+		fallback = "qcom";
+		break;
+	case NODE_TYPE_SOC:
+		node_name = META_NODE_SOC;
+		prop_name = PROP_MSM_ID;
+		match_values[0] = params->chip_id;
+		masks[0] = 0xffff;
+		num_match_values = 1;
+		log_type = "SOC";
+		break;
+	case NODE_TYPE_SOCVER:
+		node_name = META_NODE_SOCVER;
+		prop_name = PROP_SOCVER_ID;
+		match_values[0] = params->chip_version;
+		num_match_values = 1;
+		log_type = "SOCVER";
+		break;
+	case NODE_TYPE_BOARD:
+		node_name = META_NODE_BOARD;
+		prop_name = PROP_BOARD_ID;
+		match_values[0] = params->platform;
+		log_type = "Board";
+		break;
+	case NODE_TYPE_BOARDREV:
+		node_name = META_NODE_BOARDREV;
+		prop_name = PROP_BOARDREV_ID;
+		match_values[0] = params->board_version;
+		num_match_values = 1;
+		log_type = "BoardRev";
+		break;
+	case NODE_TYPE_PERIPHERAL:
+		node_name = META_NODE_BOARD_SUBTYPE_PERIPHERAL;
+		prop_name = PROP_BOARD_SUBTYPE;
+		match_values[0] = params->subtype;
+		log_type = "Peripheral Subtype";
+		break;
+	case NODE_TYPE_STORAGE:
+		node_name = META_NODE_BOARD_SUBTYPE_STORAGE;
+		prop_name = PROP_BOARD_SUBTYPE;
+		match_values[0] = params->storage_type;
+		masks[0] = 0x7000;
+		shifts[0] = 12;
+		log_type = "Storage";
+		break;
+	case NODE_TYPE_DDR_SIZE:
+		node_name = META_NODE_BOARD_SUBTYPE_DDR_SIZE;
+		prop_name = PROP_BOARD_SUBTYPE;
+		match_values[0] = params->ddr_size_type;
+		masks[0] = 0xf00;
+		shifts[0] = 8;
+		log_type = "DDR Size";
+		break;
+	case NODE_TYPE_SOFTSKU:
+		node_name = META_NODE_SOFTSKU;
+		prop_name = PROP_SOFTSKU_ID;
+		match_values[0] = params->softsku_id;
+		log_type = "SoftSKU";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	node_offset = fdt_subnode_offset(metadata, root_offset, node_name);
+	if (node_offset < 0) {
+		log_debug("%s node not found\n", log_type);
+		return node_offset;
+	}
+
+	fdt_for_each_subnode(subnode, metadata, node_offset) {
+		const u32 *prop = fdt_getprop(metadata, subnode, prop_name, &len);
+
+		if (!prop || len < (int)(num_match_values * sizeof(u32)))
+			continue;
+
+		all_match = true;
+		for (i = 0; i < num_match_values; i++) {
+			u32 dtb_value = fdt32_to_cpu(prop[i]);
+
+			dtb_value = (dtb_value & masks[i]) >> shifts[i];
+
+			if (dtb_value != match_values[i]) {
+				all_match = false;
+				break;
+			}
+		}
+
+		if (!all_match)
+			continue;
+
+		subnode_name = fdt_get_name(metadata, subnode, &name_len);
+		if (subnode_name) {
+			log_match_values(log_type, subnode_name, num_match_values,
+					 match_values);
+			return add_to_bucket(subnode_name, name_len, bucket_head);
+		}
+	}
+
+	if (fallback) {
+		log_info("No %s match, using fallback '%s'\n", log_type, fallback);
+		return add_to_bucket(fallback, strlen(fallback), bucket_head);
+	}
+
+	log_debug("No %s match\n", log_type);
+
+	return -ENOENT;
+}
+
+/**
+ * qcom_build_bucket_list() - Build bucket list from metadata DTB
+ * @metadata: Metadata DTB pointer
+ * @params: Hardware parameters
+ * @bucket_head: Bucket list head
+ *
+ * This function parses the metadata DTB and builds a list of matching
+ * node names based on the detected hardware parameters.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_build_bucket_list(void *metadata,
+				  struct qcom_hw_params *params,
+				  struct list_head *bucket_head)
+{
+	int root_offset;
+	int ret;
+	struct bucket_node *node;
+
+	log_debug("Building bucket list from hardware parameters\n");
+
+	root_offset = fdt_path_offset(metadata, "/");
+	if (root_offset < 0) {
+		log_err("Failed to find root node in metadata DTB\n");
+		return root_offset;
+	}
+
+	ret = process_node(NODE_TYPE_OEM, metadata, root_offset,
+			   params, bucket_head);
+	if (ret < 0 && ret != -ENOENT)
+		return ret;
+
+	ret = process_node(NODE_TYPE_SOC, metadata, root_offset,
+			   params, bucket_head);
+	if (ret < 0 && ret != -ENOENT)
+		return ret;
+
+	ret = process_node(NODE_TYPE_SOCVER, metadata, root_offset,
+			   params, bucket_head);
+	if (ret < 0 && ret != -ENOENT)
+		return ret;
+
+	ret = process_node(NODE_TYPE_BOARD, metadata, root_offset,
+			   params, bucket_head);
+	if (ret < 0 && ret != -ENOENT)
+		return ret;
+
+	ret = process_node(NODE_TYPE_BOARDREV, metadata, root_offset,
+			   params, bucket_head);
+	if (ret < 0 && ret != -ENOENT)
+		return ret;
+
+	process_node(NODE_TYPE_PERIPHERAL, metadata, root_offset,
+		     params, bucket_head);
+
+	process_node(NODE_TYPE_STORAGE, metadata, root_offset,
+		     params, bucket_head);
+
+	process_node(NODE_TYPE_DDR_SIZE, metadata, root_offset,
+		     params, bucket_head);
+
+	process_node(NODE_TYPE_SOFTSKU, metadata, root_offset,
+		     params, bucket_head);
+
+	log_debug("Bucket list: ");
+	list_for_each_entry(node, bucket_head, list)
+		log_debug("%s ", node->name);
+	log_debug("\n");
+
+	return 0;
+}
+
+/**
+ * qcom_load_fit_image() - Load FIT image from EFI partition
+ * @fitp: Pointer to store FIT image address
+ * @fit_sizep: Pointer to store FIT image size
+ *
+ * This function loads qclinux_fit.img from the EFI partition using the
+ * EFI Simple File System Protocol, matching the pattern from efi_fdt.c
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_load_fit_image(void **fitp, efi_uintn_t *fit_sizep)
+{
+	efi_status_t ret;
+	efi_handle_t *volume_handles = NULL;
+	efi_uintn_t count;
+	struct efi_handler *handler;
+	struct efi_simple_file_system_protocol *fs;
+	struct efi_file_handle *root = NULL;
+	struct efi_file_handle *file = NULL;
+	u16 fit_name[] = u"/qclinux_fit.img";
+	u32 i;
+
+	log_info("%s: Loading FIT image from EFI partition\n", __func__);
+
+	ret = efi_locate_handle_buffer_int(BY_PROTOCOL,
+					   &efi_simple_file_system_protocol_guid,
+					   NULL, &count, &volume_handles);
+	if (ret != EFI_SUCCESS) {
+		log_err("Failed to locate file system volumes: %lu\n", ret);
+		return -EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		ret = efi_search_protocol(volume_handles[i],
+					  &efi_simple_file_system_protocol_guid,
+					  &handler);
+		if (ret != EFI_SUCCESS)
+			continue;
+
+		ret = efi_protocol_open(handler, (void **)&fs, efi_root, NULL,
+					EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+		if (ret != EFI_SUCCESS)
+			continue;
+
+		ret = EFI_CALL(fs->open_volume(fs, &root));
+		if (ret != EFI_SUCCESS)
+			continue;
+
+		ret = EFI_CALL(root->open(root, &file, fit_name,
+					  EFI_FILE_MODE_READ, 0));
+		if (ret == EFI_SUCCESS) {
+			log_info("%s: %ls found!\n", __func__, fit_name);
+			break;
+		}
+
+		EFI_CALL(root->close(root));
+		root = NULL;
+	}
+
+	if (!file) {
+		log_err("FIT image not found on any volume\n");
+		efi_free_pool(volume_handles);
+		return -ENOENT;
+	}
+
+	ret = efi_file_size(file, fit_sizep);
+	if (ret != EFI_SUCCESS) {
+		log_err("Failed to get FIT file size: %lu\n", ret);
+		goto out;
+	}
+
+	log_info("FIT image size: %lu bytes\n", *fit_sizep);
+
+	ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+				 EFI_BOOT_SERVICES_DATA,
+				 efi_size_in_pages(*fit_sizep),
+				 (efi_physical_addr_t *)fitp);
+	if (ret != EFI_SUCCESS) {
+		log_err("Failed to allocate memory for FIT image: %lu\n", ret);
+		goto out;
+	}
+
+	ret = EFI_CALL(file->read(file, fit_sizep, *fitp));
+	if (ret != EFI_SUCCESS) {
+		log_err("Failed to read FIT image: %lu\n", ret);
+		efi_free_pages((uintptr_t)*fitp, efi_size_in_pages(*fit_sizep));
+		*fitp = NULL;
+	}
+
+out:
+	if (file)
+		EFI_CALL(file->close(file));
+	if (root)
+		EFI_CALL(root->close(root));
+	efi_free_pool(volume_handles);
+
+	return ret;
+}
+
+/**
+ * qcom_extract_metadata_dtb() - Extract metadata DTB from FIT image
+ * @fit: FIT image pointer
+ * @metadata: Pointer to store metadata DTB address
+ * @metadata_size: Pointer to store metadata DTB size
+ *
+ * The metadata DTB is the first image in the FIT (fdt-0).
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_extract_metadata_dtb(void *fit, void **metadata,
+				     size_t *metadata_size)
+{
+	int images_node, first_image;
+	const void *data;
+	size_t size;
+	int ret;
+
+	images_node = fdt_path_offset(fit, FIT_IMAGES_PATH);
+	if (images_node < 0) {
+		log_err("Cannot find /images node in FIT\n");
+		return images_node;
+	}
+
+	first_image = fdt_first_subnode(fit, images_node);
+	if (first_image < 0) {
+		log_err("Cannot find first image in FIT\n");
+		return first_image;
+	}
+
+	ret = fit_image_get_data(fit, first_image, &data, &size);
+	if (ret) {
+		log_err("Failed to get metadata DTB data\n");
+		return ret;
+	}
+
+	*metadata = malloc(size);
+	if (!*metadata) {
+		log_err("Failed to allocate memory for metadata DTB\n");
+		return -ENOMEM;
+	}
+
+	memcpy(*metadata, data, size);
+	*metadata_size = size;
+
+	log_info("Extracted metadata DTB: %zu bytes\n", size);
+
+	return 0;
+}
+
+/**
+ * qcom_count_compatible_matches() - Count matching tokens in compatible string
+ * @compatible: Compatible string from FIT configuration
+ * @compat_len: Length of compatible string
+ * @bucket_head: Bucket list head
+ *
+ * Parses the compatible string and counts how many tokens match entries
+ * in the bucket list. The compatible string format is typically:
+ * "vendor,device-variant-subtype" where tokens are separated by commas and dashes.
+ *
+ * Return: Number of matching tokens
+ */
+static int qcom_count_compatible_matches(const char *compatible, int compat_len,
+					 struct list_head *bucket_head)
+{
+	char *compat_copy;
+	char *str_ptr;
+	char *token;
+	int match_count = 0;
+
+	compat_copy = malloc(compat_len + 1);
+	if (!compat_copy)
+		return 0;
+
+	memcpy(compat_copy, compatible, compat_len);
+	compat_copy[compat_len] = '\0';
+
+	str_ptr = compat_copy;
+
+	/* First split by comma to get vendor prefix (e.g., "qcom") */
+	token = strsep(&str_ptr, ",");
+	if (token && search_in_bucket(token, bucket_head))
+		match_count++;
+
+	/* Then split remaining parts by dash */
+	token = strsep(&str_ptr, "-");
+	while (token) {
+		if (search_in_bucket(token, bucket_head))
+			match_count++;
+		token = strsep(&str_ptr, "-");
+	}
+
+	free(compat_copy);
+	return match_count;
+}
+
+/**
+ * qcom_find_matching_config() - Find matching FIT configuration
+ * @fit: FIT image pointer
+ * @bucket_head: Bucket list head
+ * @config_node: Pointer to store matching configuration node offset
+ *
+ * This function iterates through all FIT configurations and finds the one
+ * with the most matching tokens in its compatible string against the bucket list.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_find_matching_config(void *fit, struct list_head *bucket_head,
+				     int *config_node)
+{
+	int configs_node, cfg;
+	const char *compatible;
+	int compat_len;
+	const char *cfg_name;
+	int name_len;
+	int best_match_count = 0;
+	int best_config = -1;
+	int match_count;
+
+	configs_node = fdt_path_offset(fit, FIT_CONFS_PATH);
+	if (configs_node < 0) {
+		log_err("Cannot find /configurations node in FIT\n");
+		return configs_node;
+	}
+
+	fdt_for_each_subnode(cfg, fit, configs_node) {
+		cfg_name = fdt_get_name(fit, cfg, &name_len);
+		compatible = fdt_getprop(fit, cfg, PROP_COMPATIBLE, &compat_len);
+
+		if (!compatible || compat_len <= 0) {
+			log_debug("Config %s has no compatible property\n", cfg_name);
+			continue;
+		}
+
+		log_debug("Checking config: %s, compatible: %s\n",
+			  cfg_name, compatible);
+
+		match_count = qcom_count_compatible_matches(compatible, compat_len,
+							    bucket_head);
+
+		log_debug("Config %s: %d matches\n", cfg_name, match_count);
+
+		if (match_count > best_match_count) {
+			best_match_count = match_count;
+			best_config = cfg;
+		}
+	}
+
+	if (best_config < 0) {
+		log_err("No matching configuration found\n");
+		return -ENOENT;
+	}
+
+	cfg_name = fdt_get_name(fit, best_config, &name_len);
+	compatible = fdt_getprop(fit, best_config, PROP_COMPATIBLE, &compat_len);
+	log_info("Selected configuration: %s (compatible: %s, matches: %d)\n",
+		 cfg_name, compatible, best_match_count);
+
+	*config_node = best_config;
+	return 0;
+}
+
+/**
+ * qcom_get_fdt_image_data() - Get FDT image data from FIT
+ * @fit: FIT image pointer
+ * @images_node: Images node offset
+ * @fdt_name: FDT image name to load
+ * @fdt_datap: Pointer to store FDT data address
+ * @fdt_sizep: Pointer to store FDT data size
+ *
+ * Helper function to load an FDT image from the FIT by name.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_get_fdt_image_data(void *fit, int images_node,
+				   const char *fdt_name,
+				   const void **fdt_datap, size_t *fdt_sizep)
+{
+	int fdt_node;
+	int ret;
+
+	fdt_node = fdt_subnode_offset(fit, images_node, fdt_name);
+	if (fdt_node < 0) {
+		log_err("Cannot find FDT node: %s\n", fdt_name);
+		return fdt_node;
+	}
+
+	ret = fit_image_get_data(fit, fdt_node, fdt_datap, fdt_sizep);
+	if (ret) {
+		log_err("Failed to get FDT data for %s\n", fdt_name);
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * qcom_load_dtb_with_overlays() - Load DTB and apply overlays
+ * @fit: FIT image pointer
+ * @config_node: Configuration node offset
+ * @final_dtb: Pointer to store final DTB address
+ * @final_dtb_size: Pointer to store final DTB size
+ *
+ * This function loads the base DTB and applies all DTBOs specified in the
+ * configuration's "fdt" property.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_load_dtb_with_overlays(void *fit, int config_node,
+				       void **final_dtb,
+				       size_t *final_dtb_size)
+{
+	int images_node;
+	const char *fdt_name;
+	int fdt_name_len;
+	const void *fdt_data;
+	size_t fdt_size;
+	void *base_dtb = NULL;
+	size_t base_dtb_size = 0;
+	phys_addr_t dtb_addr;
+	int i, ret;
+	int fixups_offset;
+
+	images_node = fdt_path_offset(fit, FIT_IMAGES_PATH);
+	if (images_node < 0)
+		return images_node;
+
+	fdt_name = fdt_stringlist_get(fit, config_node, PROP_FDT, 0, &fdt_name_len);
+	if (!fdt_name) {
+		log_err("No fdt property in configuration\n");
+		return -EINVAL;
+	}
+
+	printf("DTB: %s\n", fdt_name);
+
+	ret = qcom_get_fdt_image_data(fit, images_node, fdt_name,
+				      &fdt_data, &fdt_size);
+	if (ret)
+		return ret;
+
+	/* Allocate base DTB with extra space for overlays using LMB */
+	base_dtb_size = fdt_size + (8 * 1024); /* Add 8KB for overlays */
+	ret = lmb_alloc(base_dtb_size, &dtb_addr);
+	if (ret) {
+		log_err("Failed to allocate LMB memory for base DTB: %zu bytes\n", base_dtb_size);
+		return -ENOMEM;
+	}
+	base_dtb = (void *)dtb_addr;
+
+	memcpy(base_dtb, fdt_data, fdt_size);
+	ret = fdt_open_into(base_dtb, base_dtb, base_dtb_size);
+	if (ret) {
+		log_err("Failed to open DTB: %d\n", ret);
+		return ret;
+	}
+
+	/* Apply overlays (remaining fdt entries) */
+	for (i = 1; ; i++) {
+		fdt_name = fdt_stringlist_get(fit, config_node, PROP_FDT, i,
+					      &fdt_name_len);
+		if (!fdt_name)
+			break;
+
+		log_info("Applying overlay: %s\n", fdt_name);
+
+		ret = qcom_get_fdt_image_data(fit, images_node, fdt_name,
+					      &fdt_data, &fdt_size);
+		if (ret)
+			continue;
+
+		fixups_offset = fdt_path_offset(fdt_data, "/__fixups__");
+		if (fixups_offset == -FDT_ERR_NOTFOUND) {
+			log_warning("%s is not a valid overlay (no __fixups__)\n", fdt_name);
+			continue;
+		}
+
+		ret = fdt_overlay_apply_verbose(base_dtb, (void *)fdt_data);
+		if (ret)
+			log_err("Failed to apply overlay %s: %d\n", fdt_name, ret);
+	}
+
+	ret = fdt_pack(base_dtb);
+	if (ret) {
+		log_err("Failed to pack DTB: %d\n", ret);
+		return ret;
+	}
+
+	*final_dtb = base_dtb;
+	*final_dtb_size = fdt_totalsize(base_dtb);
+
+	log_info("Final DTB size: %zu bytes\n", *final_dtb_size);
+
+	return 0;
+}
+
+/**
+ * qcom_fit_multidtb_setup() - Main entry point for FIT multi-DTB selection
+ *
+ * This is the main function that orchestrates the entire DTB selection process:
+ * 1. Load qclinux_fit.img from EFI partition
+ * 2. Extract metadata DTB
+ * 3. Detect hardware parameters from SMEM
+ * 4. Build bucket list from metadata
+ * 5. Find matching FIT configuration
+ * 6. Load DTB and apply overlays
+ * 7. Install FDT for EFI
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int qcom_fit_multidtb_setup(void)
+{
+	void *fit = NULL;
+	efi_uintn_t fit_size = 0;
+	void *metadata = NULL;
+	size_t metadata_size = 0;
+	struct qcom_hw_params hw_params;
+	LIST_HEAD(bucket_list);
+	int config_node;
+	void *final_dtb = NULL;
+	size_t final_dtb_size = 0;
+	int ret;
+
+	log_debug("=== FIT Multi-DTB Selection ===\n");
+
+	log_debug("Loading FIT image\n");
+	ret = qcom_load_fit_image(&fit, &fit_size);
+	if (ret) {
+		log_err("Failed to load FIT image\n");
+		goto cleanup_fit;
+	}
+
+	ret = fdt_check_header(fit);
+	if (ret) {
+		log_err("Invalid FIT header\n");
+		ret = -EINVAL;
+		goto cleanup_fit;
+	}
+
+	ret = fit_check_format(fit, IMAGE_SIZE_INVAL);
+	if (ret) {
+		log_err("Invalid FIT format\n");
+		ret = -EINVAL;
+		goto cleanup_fit;
+	}
+
+	log_debug("Extracting metadata DTB\n");
+	ret = qcom_extract_metadata_dtb(fit, &metadata, &metadata_size);
+	if (ret) {
+		log_err("Failed to extract metadata DTB\n");
+		goto cleanup_metadata;
+	}
+
+	log_debug("Detecting hardware parameters\n");
+	ret = qcom_detect_hardware_params(&hw_params);
+	if (ret) {
+		log_err("Failed to detect hardware parameters\n");
+		goto cleanup_metadata;
+	}
+
+	log_debug("Building bucket list\n");
+	ret = qcom_build_bucket_list(metadata, &hw_params, &bucket_list);
+	if (ret) {
+		log_err("Failed to build bucket list\n");
+		goto cleanup_bucket;
+	}
+
+	log_debug("Finding matching configuration\n");
+	ret = qcom_find_matching_config(fit, &bucket_list, &config_node);
+	if (ret) {
+		log_err("Failed to find matching configuration\n");
+		goto cleanup_bucket;
+	}
+
+	log_debug("Loading DTB and applying overlays\n");
+	ret = qcom_load_dtb_with_overlays(fit, config_node, &final_dtb,
+					  &final_dtb_size);
+	if (ret) {
+		log_err("Failed to load DTB with overlays\n");
+		goto cleanup_dtb;
+	}
+
+	log_debug("Setting fdt_addr to selected DTB address\n");
+
+	ret = fdt_check_header(final_dtb);
+	if (ret) {
+		log_err("Invalid final DTB header: %d\n", ret);
+		ret = -EINVAL;
+		goto cleanup_dtb;
+	}
+
+	/* Update fdt_addr environment variable to point to our DTB */
+	env_set_hex("fdt_addr", (ulong)final_dtb);
+	log_info("Updated fdt_addr=0x%lx, DTB size=%zu bytes\n", (ulong)final_dtb, final_dtb_size);
+	log_info("EFI boot flow will use DTB directly from this address\n");
+
+	/* Don't free final_dtb - LMB manages memory and EFI boot flow will use it */
+	final_dtb = NULL;
+
+	log_debug("=== FIT Multi-DTB Selection Complete ===\n");
+
+	ret = 0;
+	goto cleanup_success;
+
+cleanup_dtb:
+	if (ret && final_dtb)
+		final_dtb = NULL;
+
+cleanup_success:
+cleanup_bucket:
+	free_bucket_list(&bucket_list);
+
+cleanup_metadata:
+	if (metadata)
+		free(metadata);
+
+cleanup_fit:
+	if (fit)
+		efi_free_pages((uintptr_t)fit, efi_size_in_pages(fit_size));
+
+	return ret;
+}
diff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.h b/arch/arm/mach-snapdragon/qcom_fit_multidtb.h
new file mode 100644
index 00000000000..b568d31777e
--- /dev/null
+++ b/arch/arm/mach-snapdragon/qcom_fit_multidtb.h
@@ -0,0 +1,189 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Qualcomm FIT Multi-DTB Selection
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * This implements automatic DTB selection from FIT images based on hardware
+ * detection via SMEM.
+ */
+
+#ifndef __QCOM_FIT_MULTIDTB_H__
+#define __QCOM_FIT_MULTIDTB_H__
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/sizes.h>
+
+/* DDR size thresholds */
+#define DDR_128MB      SZ_128M
+#define DDR_256MB      SZ_256M
+#define DDR_512MB      SZ_512M
+#define DDR_1024MB     SZ_1G
+#define DDR_2048MB     SZ_2G
+#define DDR_3072MB     (SZ_2G + SZ_1G)
+#define DDR_4096MB     SZ_4G
+
+/* DDR type enum */
+enum ddr_type {
+	DDRTYPE_256MB = 1,
+	DDRTYPE_512MB,		/* 2 */
+	DDRTYPE_1024MB,		/* 3 */
+	DDRTYPE_2048MB,		/* 4 */
+	DDRTYPE_3072MB,		/* 5 */
+	DDRTYPE_4096MB,		/* 6 */
+	DDRTYPE_128MB,		/* 7 */
+};
+
+/* Storage type enum */
+enum mem_card_type {
+	UFS = 0,
+	EMMC = 1,
+	NAND = 2,
+	STORAGE_UNKNOWN,
+};
+
+/* Boot device types from shared IMEM */
+enum boot_media_type {
+	NO_FLASH         = 0,
+	NOR_FLASH        = 1,
+	NAND_FLASH       = 2,
+	ONENAND_FLASH    = 3,
+	SDC_FLASH        = 4,
+	MMC_FLASH        = 5,
+	SPI_FLASH        = 6,
+	PCIE_FLASHLESS   = 7,
+	UFS_FLASH        = 8,
+	RESERVED_0_FLASH = 9,
+	RESERVED_1_FLASH = 10,
+	USB_FLASHLESS    = 11
+};
+
+/* Shared IMEM constants */
+#define BOOT_SHARED_IMEM_MAGIC_NUM    0xc1f8db40
+#define BOOT_SHARED_IMEM_VERSION_NUM  0x3
+
+/**
+ * struct qcom_imem_info - SoC-specific shared IMEM cookie address mapping
+ * @compatible: SoC compatible string (e.g., "qcom,qcs6490")
+ * @shared_imem_addr: Physical address of the boot shared IMEM cookie
+ *
+ * The shared IMEM cookie is populated by the bootloader and contains
+ * boot device type and other boot parameters. Its location varies per SoC
+ * and is calculated as: SCL_IMEM_BASE + IMEM_SIZE - 0x1000 (4KB cookie).
+ * Only SoCs with CONFIG_QCOM_FIT_MULTIDTB support are listed here.
+ */
+struct qcom_imem_info {
+	const char *compatible;
+	uintptr_t shared_imem_addr;
+};
+
+/*
+ * Per-SoC shared IMEM cookie address table.
+ * Address = SCL_IMEM_BASE(0x14680000) + IMEM_SIZE - 0x1000
+ *   QCM6490/QCS6490/QCS615: IMEM_SIZE=0x2B000 -> 0x146aa000
+ *   QCS9100:                IMEM_SIZE=0x59000 -> 0x146d8000
+ */
+static const struct qcom_imem_info qcom_imem_table[] = {
+	{ "qcom,qcm6490", 0x146aa000 },
+	{ "qcom,qcs6490", 0x146aa000 },
+	{ "qcom,qcs615",  0x146aa000 },
+	{ "qcom,qcs9100", 0x146d8000 },
+	{ }
+};
+
+/* Boot shared IMEM cookie structure */
+struct boot_imem_cookie {
+	u32 shared_imem_magic;
+	u32 shared_imem_version;
+	u64 etb_buf_addr;
+	u64 l2_cache_dump_buff_addr;
+	u32 a64_pointer_padding;
+	u32 uefi_ram_dump_magic;
+	u32 ddr_training_cookie;
+	u32 abnormal_reset_occurred;
+	u32 reset_status_register;
+	u32 rpm_sync_cookie;
+	u32 debug_config;
+	u64 boot_log_addr;
+	u32 boot_log_size;
+	u32 boot_fail_count;
+	u32 sbl1_error_type;
+	u32 uefi_image_magic;
+	u32 boot_device_type;
+	u64 boot_devtree_addr;
+	u64 boot_devtree_size;
+};
+
+/**
+ * struct qcom_hw_params - Hardware parameters detected from SMEM
+ * @chip_id: SoC chip ID (from socinfo->id)
+ * @chip_version: SoC version (from socinfo->plat_ver)
+ * @platform: Hardware platform ID (from socinfo->hw_plat)
+ * @subtype: Hardware platform subtype (from socinfo->hw_plat_subtype)
+ * @oem_variant_id: OEM variant ID (from socinfo->oem_variant)
+ * @ddr_size_type: DDR size type (0-10, calculated from RAM partitions)
+ * @storage_type: Storage type (UFS=1, EMMC=2, NAND=3)
+ * @foundry_id: Foundry ID (from socinfo->foundry_id)
+ * @softsku_id: Software SKU ID (if available)
+ *
+ * This structure holds all hardware parameters needed for DTB selection.
+ */
+struct qcom_hw_params {
+	u32 chip_id;
+	u32 chip_version;
+	u32 platform;
+	u32 board_version;
+	u32 subtype;
+	u32 oem_variant_id;
+	u32 ddr_size_type;
+	u32 storage_type;
+	u32 foundry_id;
+	u32 softsku_id;
+};
+
+/**
+ * struct bucket_node - Node in the bucket list
+ * @list: List head for linking nodes
+ * @name: Node name string (e.g., "qcom", "sa8775p-v2", "ride", "ufs", "8gb")
+ *
+ * The bucket list contains all matching node names from the metadata DTB.
+ * These are used to match against FIT configuration compatible strings.
+ */
+struct bucket_node {
+	struct list_head list;
+	char *name;
+};
+
+/* Node processing types for metadata DTB parsing */
+enum node_process_type {
+	NODE_TYPE_OEM,
+	NODE_TYPE_SOC,
+	NODE_TYPE_SOCVER,
+	NODE_TYPE_BOARD,
+	NODE_TYPE_BOARDREV,
+	NODE_TYPE_PERIPHERAL,
+	NODE_TYPE_STORAGE,
+	NODE_TYPE_DDR_SIZE,
+	NODE_TYPE_SOFTSKU,
+};
+
+/* Function prototypes */
+
+/**
+ * qcom_fit_multidtb_setup() - Main entry point for FIT multi-DTB selection
+ *
+ * This function:
+ * 1. Loads qclinux_fit.img from EFI partition
+ * 2. Extracts metadata DTB
+ * 3. Detects hardware parameters from SMEM
+ * 4. Builds bucket list from metadata
+ * 5. Finds matching FIT configuration
+ * 6. Loads DTB and applies overlays
+ * 7. Sets FDT for EFI
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int qcom_fit_multidtb_setup(void);
+
+#endif /* __QCOM_FIT_MULTIDTB_H__ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 3/7] configs: snapdragon: Enable FIT multi-DTB and configure IMEM
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
  2026-04-17 12:09 ` [PATCH v3 1/7] mach-snapdragon: Add generic SMEM cache infrastructure Aswin Murugan
  2026-04-17 12:09 ` [PATCH v3 2/7] mach-snapdragon: Add FIT multi-DTB selection support Aswin Murugan
@ 2026-04-17 12:09 ` Aswin Murugan
  2026-04-20  4:06   ` Simon Glass
  2026-04-17 12:09 ` [PATCH v3 4/7] image: add IH_TYPE_FATFS image type Aswin Murugan
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Aswin Murugan @ 2026-04-17 12:09 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Enable CONFIG_QCOM_FIT_MULTIDTB by default for Qualcomm Snapdragon
platforms to provide automatic DTB selection from qclinux_fit.img
with overlay support.

This allows U-Boot to automatically select the appropriate device
tree based on hardware parameters detected from SMEM, improving
boot compatibility across different hardware variants and reducing
the need for board-specific DTB selection logic.

Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
---
 configs/qcom_defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig
index baad5f09455..36ec8a50a63 100644
--- a/configs/qcom_defconfig
+++ b/configs/qcom_defconfig
@@ -12,6 +12,7 @@ CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
 CONFIG_BUTTON_CMD=y
 CONFIG_FIT=y
 CONFIG_FIT_VERBOSE=y
+CONFIG_QCOM_FIT_MULTIDTB=y
 CONFIG_BOOTSTD_FULL=y
 # CONFIG_BOOTMETH_VBE is not set
 CONFIG_BOOTDELAY=1
@@ -48,6 +49,7 @@ CONFIG_CMD_RNG=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_LOG=y
 CONFIG_OF_LIVE=y
+CONFIG_OF_LIBFDT_OVERLAY=y
 CONFIG_OF_UPSTREAM_BUILD_VENDOR=y
 CONFIG_ENV_USE_DEFAULT_ENV_TEXT_FILE=y
 CONFIG_ENV_DEFAULT_ENV_TEXT_FILE="board/qualcomm/default.env"
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 4/7] image: add IH_TYPE_FATFS image type
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
                   ` (2 preceding siblings ...)
  2026-04-17 12:09 ` [PATCH v3 3/7] configs: snapdragon: Enable FIT multi-DTB and configure IMEM Aswin Murugan
@ 2026-04-17 12:09 ` Aswin Murugan
  2026-04-20  4:06   ` Simon Glass
  2026-04-17 12:09 ` [PATCH v3 5/7] mkimage: add fatfs image type for FAT partition images Aswin Murugan
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Aswin Murugan @ 2026-04-17 12:09 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Add a new image type IH_TYPE_FATFS to represent a raw FAT
filesystem partition image. Register the type in the image
type lookup table with short name "fatfs" and description
"FAT Filesystem Image".

Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
---
 boot/image.c    | 1 +
 include/image.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/boot/image.c b/boot/image.c
index 185d52ba492..4a17da645cf 100644
--- a/boot/image.c
+++ b/boot/image.c
@@ -136,6 +136,7 @@ static const table_entry_t uimage_type[] = {
 	{	IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image",	},
 	{	IH_TYPE_FIRMWARE,   "firmware",	  "Firmware",		},
 	{	IH_TYPE_FLATDT,     "flat_dt",    "Flat Device Tree",	},
+	{	IH_TYPE_FATFS,      "fatfs",      "FAT Filesystem Image",	},
 	{	IH_TYPE_GPIMAGE,    "gpimage",    "TI Keystone SPL Image",},
 	{	IH_TYPE_KERNEL,	    "kernel",	  "Kernel Image",	},
 	{	IH_TYPE_KERNEL_NOLOAD, "kernel_noload",  "Kernel Image (no loading done)", },
diff --git a/include/image.h b/include/image.h
index 34efac6056d..68469685c4c 100644
--- a/include/image.h
+++ b/include/image.h
@@ -235,6 +235,7 @@ enum image_type_t {
 	IH_TYPE_TFA_BL31,		/* TFA BL31 image */
 	IH_TYPE_STM32IMAGE_V2,		/* STMicroelectronics STM32 Image V2.0 */
 	IH_TYPE_AMLIMAGE,		/* Amlogic Boot Image */
+	IH_TYPE_FATFS,			/* FAT Filesystem Image */
 
 	IH_TYPE_COUNT,			/* Number of image types */
 };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 5/7] mkimage: add fatfs image type for FAT partition images
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
                   ` (3 preceding siblings ...)
  2026-04-17 12:09 ` [PATCH v3 4/7] image: add IH_TYPE_FATFS image type Aswin Murugan
@ 2026-04-17 12:09 ` Aswin Murugan
  2026-04-20  4:06   ` Simon Glass
  2026-04-17 12:09 ` [PATCH v3 6/7] doc: document mkimage fatfs type and Qualcomm multi-DTB Aswin Murugan
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Aswin Murugan @ 2026-04-17 12:09 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Add a new mkimage image type 'fatfs' that creates a raw FAT
filesystem partition image from a directory of files.

The image handler (fatimage.c) uses mkfs.vfat (dosfstools)
to format the image and mcopy (mtools) to populate it. The
image size is calculated automatically from the input
directory size plus FAT metadata overhead.

New long options added to mkimage:
  --fat-extra-space <KB>  extra padding (default: 512 KB)
  --fat-type <0|12|16|32> FAT type (0 = auto-detect)
  --fat-volume-id <label> volume label (default: BOOT)
  --fat-mkfs-opts <opts>  extra mkfs.vfat options

Usage:
  mkimage -T fatfs -d <input-dir> \
      --fat-extra-space 512 \
      --fat-volume-id "MYBOOT" \
      --fat-mkfs-opts "-S 512 -a" \
      output.img

Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
---
 tools/Makefile   |   1 +
 tools/fatimage.c | 495 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/fatimage.h |  25 +++
 tools/mkimage.c  |  21 ++
 tools/mkimage.h  |  15 ++
 5 files changed, 557 insertions(+)
 create mode 100644 tools/fatimage.c
 create mode 100644 tools/fatimage.h

diff --git a/tools/Makefile b/tools/Makefile
index 1a5f425ecda..2f6c9363209 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -112,6 +112,7 @@ ROCKCHIP_OBS = generated/lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
 dumpimage-mkimage-objs := aisimage.o \
 			amlimage.o \
 			atmelimage.o \
+			fatimage.o \
 			$(FIT_OBJS-y) \
 			$(FIT_SIG_OBJS-y) \
 			$(FIT_CIPHER_OBJS-y) \
diff --git a/tools/fatimage.c b/tools/fatimage.c
new file mode 100644
index 00000000000..6a199c70f5b
--- /dev/null
+++ b/tools/fatimage.c
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * FAT Filesystem Image support for mkimage
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
+ *
+ * This tool creates FAT filesystem images from a directory of files.
+ * It uses system tools (mkfs.vfat and mcopy from mtools) to create
+ * the filesystem image.
+ */
+
+#include "imagetool.h"
+#include "mkimage.h"
+#include "fatimage.h"
+#include <image.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+
+static struct fatimage_params fatparams = {
+	.input_dir = NULL,
+	.extra_space = 512,
+	.fat_type = 0,
+	.volume_id = "BOOT",
+	.mkfs_opts = "-S 512",
+};
+
+/* Cached image size to avoid recalculation between vrec_header and set_header */
+static int cached_image_size_kb = -1;
+
+/**
+ * get_directory_size_kb() - Return the total disk usage of a directory in KB
+ * @path: Path to the directory
+ *
+ * Runs 'du -sk' to measure the on-disk size of all files under @path.
+ *
+ * Return: size in KB on success, -1 on error
+ */
+static int get_directory_size_kb(const char *path)
+{
+	char cmd[1024];
+	FILE *fp;
+	int size_kb = 0;
+
+	snprintf(cmd, sizeof(cmd), "du -sk \"%s\" 2>/dev/null | cut -f1", path);
+
+	fp = popen(cmd, "r");
+	if (!fp) {
+		fprintf(stderr, "Error: Failed to execute du command\n");
+		return -1;
+	}
+
+	if (fscanf(fp, "%d", &size_kb) != 1) {
+		fprintf(stderr, "Error: Failed to read directory size\n");
+		pclose(fp);
+		return -1;
+	}
+
+	pclose(fp);
+	return size_kb;
+}
+
+/**
+ * count_entries() - Recursively count files and subdirectories under a path
+ * @path: Directory to scan
+ * @files: Incremented for each regular file found
+ * @dirs: Incremented for each subdirectory found
+ *
+ * Used to estimate FAT directory entry overhead when sizing the image.
+ *
+ * Return: 0 on success, -1 if the directory cannot be opened
+ */
+static int count_entries(const char *path, int *files, int *dirs)
+{
+	DIR *dir;
+	struct dirent *entry;
+	struct stat st;
+	char full_path[1024];
+
+	dir = opendir(path);
+	if (!dir) {
+		fprintf(stderr, "Error: Cannot open directory %s: %s\n",
+			path, strerror(errno));
+		return -1;
+	}
+
+	while ((entry = readdir(dir)) != NULL) {
+		if (strcmp(entry->d_name, ".") == 0 ||
+		    strcmp(entry->d_name, "..") == 0)
+			continue;
+
+		snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
+
+		if (stat(full_path, &st) < 0) {
+			fprintf(stderr, "Warning: Cannot stat %s: %s\n",
+				full_path, strerror(errno));
+			continue;
+		}
+
+		if (S_ISDIR(st.st_mode)) {
+			(*dirs)++;
+			count_entries(full_path, files, dirs);
+		} else {
+			(*files)++;
+		}
+	}
+
+	closedir(dir);
+	return 0;
+}
+
+/**
+ * calculate_image_size() - Compute the required FAT image size in KB
+ * @input_dir: Directory whose contents will be packed into the image
+ * @extra_space: Additional padding in KB to add beyond the data size
+ * @fat_type: Requested FAT type (0=auto, 12, 16, 32)
+ *
+ * Calculates the minimum image size needed to hold all files in @input_dir
+ * plus FAT metadata overhead (directory entries, two FAT copies) and
+ * @extra_space KB of padding. The result is cached in cached_image_size_kb
+ * so that vrec_header and set_header agree on the same value.
+ *
+ * Return: image size in KB on success, -1 on error
+ */
+static int calculate_image_size(const char *input_dir, int extra_space,
+				 int fat_type)
+{
+	int data_kb;
+	int sectors;
+	int files = 0, dirs = 0;
+	int dir_bytes, fat_bytes;
+	int dir_sectors, fat_sectors;
+	int fat_entry_size;
+	int total_sectors;
+	int blocks;
+
+	if (cached_image_size_kb > 0)
+		return cached_image_size_kb;
+
+	data_kb = get_directory_size_kb(input_dir);
+	if (data_kb < 0)
+		return -1;
+
+	sectors = data_kb * 2;
+
+	if (count_entries(input_dir, &files, &dirs) < 0)
+		return -1;
+
+	dir_bytes = (files + dirs) * DIR_ENTRY_SIZE;
+	dir_bytes += dirs * DIR_ENTRY_SIZE;
+
+	if (fat_type == 32) {
+		fat_entry_size = FAT_ENTRY_SIZE_FAT32;
+		if ((sectors / 2 + extra_space) < 32 * 1024) {
+			fprintf(stderr, "Warning: Image size %d KB may be too small for FAT32\n",
+				(sectors / 2 + extra_space));
+			fprintf(stderr, "         FAT32 works best with images >= 32 MB\n");
+			fprintf(stderr, "         Consider using auto-detect or FAT16 instead\n");
+		}
+	} else if (fat_type == 0) {
+		if ((sectors / 2 + extra_space) > 512 * 1024)
+			fat_entry_size = FAT_ENTRY_SIZE_FAT32;
+		else
+			fat_entry_size = FAT_ENTRY_SIZE_FAT16;
+	} else if (fat_type == 16) {
+		fat_entry_size = FAT_ENTRY_SIZE_FAT16;
+	} else if (fat_type == 12) {
+		fat_entry_size = FAT_ENTRY_SIZE_FAT12;
+	} else {
+		fat_entry_size = FAT_ENTRY_SIZE_FAT16;
+	}
+
+	fat_bytes = sectors * fat_entry_size;
+	fat_bytes += dirs * fat_entry_size;
+
+	dir_sectors = (dir_bytes + SECTOR_SIZE - 1) / SECTOR_SIZE;
+	fat_sectors = ((fat_bytes + SECTOR_SIZE - 1) / SECTOR_SIZE) * 2;
+
+	total_sectors = sectors + dir_sectors + fat_sectors;
+	blocks = (total_sectors / 2) + extra_space;
+
+	printf("FAT image size calculation:\n");
+	printf("  Data size: %d KB (%d sectors)\n", data_kb, sectors);
+	printf("  Files: %d, Directories: %d\n", files, dirs);
+	printf("  Directory overhead: %d sectors\n", dir_sectors);
+	printf("  FAT overhead: %d sectors (2 FATs)\n", fat_sectors);
+	printf("  Extra padding: %d KB\n", extra_space);
+	printf("  Total image size: %d KB\n", blocks);
+
+	cached_image_size_kb = blocks;
+
+	return blocks;
+}
+
+/**
+ * create_fat_image() - Format a FAT image file and populate it with files
+ * @input_dir: Source directory; all contents are copied into the image
+ * @output_file: Path of the FAT image file to create
+ * @blocks: Image size in KB (passed to mkfs.vfat as the block count)
+ * @fat_type: FAT type to use (0=auto, 12, 16, 32)
+ * @volume_id: FAT volume label string
+ * @mkfs_opts: Additional options forwarded to mkfs.vfat
+ *
+ * Calls mkfs.vfat to format @output_file as a FAT filesystem, then uses
+ * mcopy to copy all files from @input_dir into the image root.
+ *
+ * Return: 0 on success, -1 on error
+ */
+static int create_fat_image(const char *input_dir, const char *output_file,
+			    int blocks, int fat_type, const char *volume_id,
+			    const char *mkfs_opts)
+{
+	char cmd[2048];
+	int ret;
+
+	unlink(output_file);
+
+	if (fat_type > 0) {
+		snprintf(cmd, sizeof(cmd),
+			 "mkfs.vfat -F %d %s -n \"%s\" -C \"%s\" %d",
+			 fat_type, mkfs_opts ? mkfs_opts : "",
+			 volume_id, output_file, blocks);
+	} else {
+		if (blocks > 512 * 1024) {
+			snprintf(cmd, sizeof(cmd),
+				 "mkfs.vfat -F 32 %s -n \"%s\" -C \"%s\" %d",
+				 mkfs_opts ? mkfs_opts : "",
+				 volume_id, output_file, blocks);
+		} else {
+			snprintf(cmd, sizeof(cmd),
+				 "mkfs.vfat %s -n \"%s\" -C \"%s\" %d",
+				 mkfs_opts ? mkfs_opts : "",
+				 volume_id, output_file, blocks);
+		}
+	}
+
+	printf("Creating FAT filesystem: %s\n", cmd);
+	ret = system(cmd);
+	if (ret != 0) {
+		fprintf(stderr, "Error: mkfs.vfat failed with code %d\n", ret);
+		fprintf(stderr, "Make sure mkfs.vfat (dosfstools) is installed\n");
+		return -1;
+	}
+
+	snprintf(cmd, sizeof(cmd),
+		 "MTOOLS_SKIP_CHECK=1 mcopy -i \"%s\" -s \"%s\"/* ::/",
+		 output_file, input_dir);
+
+	printf("Copying files: %s\n", cmd);
+	ret = system(cmd);
+	if (ret != 0) {
+		fprintf(stderr, "Error: mcopy failed with code %d\n", ret);
+		fprintf(stderr, "Make sure mcopy (mtools) is installed\n");
+		return -1;
+	}
+
+	printf("FAT image created successfully: %s\n", output_file);
+	return 0;
+}
+
+/**
+ * fatimage_check_params() - Validate mkimage parameters for the fatfs type
+ * @params: mkimage tool parameters (unused; input dir is in fatparams)
+ *
+ * Verifies that an input directory has been specified via fatimage_set_dir()
+ * and that it exists and is a directory.
+ *
+ * Return: 0 if parameters are valid, -1 on error
+ */
+static int fatimage_check_params(struct image_tool_params *params)
+{
+	if (!fatparams.input_dir) {
+		fprintf(stderr, "Error: Input directory not specified\n");
+		fprintf(stderr, "Use -d <directory> to specify input directory\n");
+		return -1;
+	}
+
+	struct stat st;
+	if (stat(fatparams.input_dir, &st) < 0) {
+		fprintf(stderr, "Error: Input directory '%s' does not exist: %s\n",
+			fatparams.input_dir, strerror(errno));
+		return -1;
+	}
+
+	if (!S_ISDIR(st.st_mode)) {
+		fprintf(stderr, "Error: '%s' is not a directory\n",
+			fatparams.input_dir);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fatimage_check_image_type() - Report whether this handler owns a given type
+ * @type: IH_TYPE_* value to check
+ *
+ * Return: EXIT_SUCCESS if @type == IH_TYPE_FATFS, EXIT_FAILURE otherwise
+ */
+static int fatimage_check_image_type(uint8_t type)
+{
+	if (type == IH_TYPE_FATFS)
+		return EXIT_SUCCESS;
+	return EXIT_FAILURE;
+}
+
+/**
+ * fatimage_verify_header() - Verify that a buffer contains a valid FAT image
+ * @ptr: Pointer to the start of the image data
+ * @image_size: Total size of the image in bytes
+ * @params: mkimage tool parameters (unused)
+ *
+ * Checks for the FAT boot sector signature (0x55AA) at bytes 510-511.
+ *
+ * Return: 0 if the signature is present, -1 otherwise
+ */
+static int fatimage_verify_header(unsigned char *ptr, int image_size,
+				  struct image_tool_params *params)
+{
+	if (image_size < 512)
+		return -1;
+
+	if (ptr[510] != 0x55 || ptr[511] != 0xAA) {
+		fprintf(stderr, "Error: Not a valid FAT filesystem image\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fatimage_print_header() - Print human-readable FAT image information
+ * @ptr: Pointer to the start of the image data
+ * @params: mkimage tool parameters (unused)
+ *
+ * Prints the boot signature, detected FAT type (FAT32 vs FAT12/16),
+ * and volume label read from the BPB.
+ */
+static void fatimage_print_header(const void *ptr,
+				  struct image_tool_params *params)
+{
+	const unsigned char *buf = ptr;
+
+	printf("FAT Filesystem Image\n");
+	printf("  Boot signature: 0x%02X%02X\n", buf[511], buf[510]);
+
+	if (buf[82] == 'F' && buf[83] == 'A' && buf[84] == 'T' &&
+	    buf[85] == '3' && buf[86] == '2') {
+		printf("  Filesystem: FAT32\n");
+		printf("  Volume label: %.11s\n", &buf[71]);
+	} else {
+		printf("  Filesystem: FAT12/FAT16\n");
+		printf("  Volume label: %.11s\n", &buf[43]);
+	}
+}
+
+/**
+ * fatimage_vrec_header() - Allocate the output buffer for the FAT image
+ * @params: mkimage tool parameters
+ * @tparams: image type parameters; hdr and header_size are set on success
+ *
+ * Called before set_header to pre-allocate a buffer large enough for the
+ * complete FAT image. The size is calculated from the input directory and
+ * cached for reuse by fatimage_set_header().
+ *
+ * Return: 0 on success, -1 on error
+ */
+static int fatimage_vrec_header(struct image_tool_params *params,
+				struct image_type_params *tparams)
+{
+	int blocks;
+	int image_size_bytes;
+
+	blocks = calculate_image_size(fatparams.input_dir,
+				      fatparams.extra_space,
+				      fatparams.fat_type);
+	if (blocks < 0) {
+		fprintf(stderr, "Error: Failed to calculate image size\n");
+		return -1;
+	}
+
+	image_size_bytes = blocks * 1024;
+
+	tparams->hdr = malloc(image_size_bytes);
+	if (!tparams->hdr) {
+		fprintf(stderr, "Error: Failed to allocate %d bytes for FAT image\n",
+			image_size_bytes);
+		return -1;
+	}
+
+	tparams->header_size = image_size_bytes;
+
+	return 0;
+}
+
+/**
+ * fatimage_set_header() - Create the FAT image and load it into the buffer
+ * @ptr: Output buffer (allocated by fatimage_vrec_header)
+ * @sbuf: stat of the output file (unused)
+ * @ifd: file descriptor of the output file (unused)
+ * @params: mkimage tool parameters; imagefile is used for the temp file name
+ *
+ * Creates the FAT image in a temporary file using mkfs.vfat and mcopy,
+ * reads the result into @ptr, then removes the temporary file.
+ *
+ * Return: 0 on success, -1 on error
+ */
+static int fatimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+			       struct image_tool_params *params)
+{
+	int blocks;
+	int ret;
+	char temp_file[256];
+	FILE *fp;
+	size_t bytes_read;
+
+	snprintf(temp_file, sizeof(temp_file), "%s.tmp", params->imagefile);
+
+	blocks = calculate_image_size(fatparams.input_dir,
+				      fatparams.extra_space,
+				      fatparams.fat_type);
+	if (blocks < 0) {
+		fprintf(stderr, "Error: Failed to calculate image size\n");
+		return -1;
+	}
+
+	ret = create_fat_image(fatparams.input_dir, temp_file,
+			       blocks, fatparams.fat_type,
+			       fatparams.volume_id, fatparams.mkfs_opts);
+	if (ret < 0) {
+		fprintf(stderr, "Error: Failed to create FAT image\n");
+		return -1;
+	}
+
+	fp = fopen(temp_file, "rb");
+	if (!fp) {
+		fprintf(stderr, "Error: Failed to open temporary file %s: %s\n",
+			temp_file, strerror(errno));
+		unlink(temp_file);
+		return -1;
+	}
+
+	bytes_read = fread(ptr, 1, blocks * 1024, fp);
+	fclose(fp);
+	unlink(temp_file);
+
+	if (bytes_read != (size_t)(blocks * 1024)) {
+		fprintf(stderr, "Error: Failed to read FAT image (read %zu, expected %d)\n",
+			bytes_read, blocks * 1024);
+		return -1;
+	}
+
+	printf("FAT image created successfully in buffer\n");
+	return 0;
+}
+
+U_BOOT_IMAGE_TYPE(
+	fatfsimage,
+	"FAT Filesystem Image",
+	0,
+	NULL,
+	fatimage_check_params,
+	fatimage_verify_header,
+	fatimage_print_header,
+	fatimage_set_header,
+	NULL,
+	fatimage_check_image_type,
+	NULL,
+	fatimage_vrec_header
+);
+
+void fatimage_set_dir(const char *dir)
+{
+	fatparams.input_dir = strdup(dir);
+}
+
+void fatimage_set_extra_space(int space_kb)
+{
+	fatparams.extra_space = space_kb;
+}
+
+void fatimage_set_fat_type(int type)
+{
+	fatparams.fat_type = type;
+}
+
+void fatimage_set_volume_id(const char *volid)
+{
+	fatparams.volume_id = strdup(volid);
+}
+
+void fatimage_set_mkfs_opts(const char *opts)
+{
+	fatparams.mkfs_opts = strdup(opts);
+}
diff --git a/tools/fatimage.h b/tools/fatimage.h
new file mode 100644
index 00000000000..8822724925c
--- /dev/null
+++ b/tools/fatimage.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * FAT Filesystem Image support for mkimage
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries
+ */
+
+#ifndef _FATIMAGE_H_
+#define _FATIMAGE_H_
+
+#define SECTOR_SIZE 512
+#define DIR_ENTRY_SIZE 32
+#define FAT_ENTRY_SIZE_FAT32 4
+#define FAT_ENTRY_SIZE_FAT16 2
+#define FAT_ENTRY_SIZE_FAT12 2  /* Rounded up from 1.5 bytes */
+
+struct fatimage_params {
+	char *input_dir;
+	int extra_space;      /* Extra padding space in KB (default: 512) */
+	int fat_type;         /* FAT type: 0=auto, 12/16/32 */
+	char *volume_id;      /* Volume label (default: "BOOT") */
+	char *mkfs_opts;      /* Extra mkfs.vfat options (default: "-S 512") */
+};
+
+#endif /* _FATIMAGE_H_ */
diff --git a/tools/mkimage.c b/tools/mkimage.c
index 3c43962807d..9fbc9b52957 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -204,6 +204,10 @@ static const struct option longopts[] = {
 	{ "tfa-bl31-addr", no_argument, NULL, 'Y' },
 	{ "tee-file", no_argument, NULL, 'z' },
 	{ "tee-addr", no_argument, NULL, 'Z' },
+{ "fat-extra-space", required_argument, NULL, OPT_FAT_EXTRA },
+	{ "fat-type", required_argument, NULL, OPT_FAT_TYPE },
+	{ "fat-volume-id", required_argument, NULL, OPT_FAT_VOLID },
+	{ "fat-mkfs-opts", required_argument, NULL, OPT_FAT_MKFS },
 	{ /* sentinel */ },
 };
 
@@ -397,6 +401,18 @@ static void process_args(int argc, char **argv)
 				exit(EXIT_FAILURE);
 			}
 			break;
+		case OPT_FAT_EXTRA:
+			fatimage_set_extra_space(atoi(optarg));
+			break;
+		case OPT_FAT_TYPE:
+			fatimage_set_fat_type(atoi(optarg));
+			break;
+		case OPT_FAT_VOLID:
+			fatimage_set_volume_id(optarg);
+			break;
+		case OPT_FAT_MKFS:
+			fatimage_set_mkfs_opts(optarg);
+			break;
 		default:
 			usage("Invalid option");
 		}
@@ -433,6 +449,11 @@ static void process_args(int argc, char **argv)
 		params.type = type;
 	}
 
+	if (params.type == IH_TYPE_FATFS && params.datafile) {
+		fatimage_set_dir(params.datafile);
+		params.skipcpy = 1;
+	}
+
 	if (!params.imagefile)
 		usage("Missing output filename");
 }
diff --git a/tools/mkimage.h b/tools/mkimage.h
index 5d6bcc9301a..599f92e617f 100644
--- a/tools/mkimage.h
+++ b/tools/mkimage.h
@@ -53,4 +53,19 @@ static inline ulong map_to_sysmem(const void *ptr)
 #define MKIMAGE_DEFAULT_DTC_OPTIONS	"-I dts -O dtb -p 500"
 #define MKIMAGE_MAX_DTC_CMDLINE_LEN	2 * MKIMAGE_MAX_TMPFILE_LEN + 35
 
+/* Long option values for mkimage */
+enum {
+	OPT_FAT_EXTRA = 512,
+	OPT_FAT_TYPE,
+	OPT_FAT_VOLID,
+	OPT_FAT_MKFS,
+};
+
+/* FAT image functions */
+void fatimage_set_dir(const char *dir);
+void fatimage_set_extra_space(int space_kb);
+void fatimage_set_fat_type(int type);
+void fatimage_set_volume_id(const char *volid);
+void fatimage_set_mkfs_opts(const char *opts);
+
 #endif /* _MKIIMAGE_H_ */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 6/7] doc: document mkimage fatfs type and Qualcomm multi-DTB
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
                   ` (4 preceding siblings ...)
  2026-04-17 12:09 ` [PATCH v3 5/7] mkimage: add fatfs image type for FAT partition images Aswin Murugan
@ 2026-04-17 12:09 ` Aswin Murugan
  2026-04-20  4:06   ` Simon Glass
  2026-04-17 12:09 ` [PATCH v3 7/7] mach-snapdragon: Reorder header includes Aswin Murugan
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Aswin Murugan @ 2026-04-17 12:09 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Update doc/mkimage.1 to document the new fatfs image type,
the --fat-* long options, a fatfs entry in the CONFIGURATION
section, and two usage examples.

Add doc/board/qualcomm/multi_dtb.rst describing the
Qualcomm FIT-based multi-DTB packaging workflow for
Snapdragon platforms. The document covers:
- FIT ITS configuration and compatible string matching
- QCOM metadata binary format and identifier properties
- Guidelines for adding new socver/boardrev entries
- Step-by-step image creation using mkimage -T fatfs

Update doc/board/qualcomm/index.rst to include the new
multi_dtb page in the toctree.

Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
---
 doc/board/qualcomm/index.rst     |   1 +
 doc/board/qualcomm/multi_dtb.rst | 352 +++++++++++++++++++++++++++++++
 doc/mkimage.1                    | 103 +++++++++
 3 files changed, 456 insertions(+)
 create mode 100644 doc/board/qualcomm/multi_dtb.rst

diff --git a/doc/board/qualcomm/index.rst b/doc/board/qualcomm/index.rst
index 3238a68e859..fe4a4aecd60 100644
--- a/doc/board/qualcomm/index.rst
+++ b/doc/board/qualcomm/index.rst
@@ -10,6 +10,7 @@ Qualcomm
    debugging
    dragonboard410c
    dragonwing
+   multi_dtb
    rb3gen2
    iq8
    phones
diff --git a/doc/board/qualcomm/multi_dtb.rst b/doc/board/qualcomm/multi_dtb.rst
new file mode 100644
index 00000000000..fa9252ce1c4
--- /dev/null
+++ b/doc/board/qualcomm/multi_dtb.rst
@@ -0,0 +1,352 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Qualcomm FIT-Based Multi-DTB Support
+=====================================
+
+Overview
+--------
+
+Qualcomm supports multiple SoCs and boards within a single software release
+binary, which requires packaging all corresponding Device Tree Blobs (DTBs)
+into a single image. To ensure the appropriate DTB(O)s are selected for each
+platform, a mechanism for dynamic device tree selection is necessary.
+
+The Flattened Image Tree (FIT) format is a standard file format for packaging
+images widely used in the community. U-Boot leverages this format to facilitate
+DTB selection and meet platform-specific requirements. The appropriate DTB
+selected for the platform by U-Boot is passed to the OS at boot time.
+
+Terminology
+-----------
+
+- **FIT**: Flattened Image Tree
+- **DT**: Device Tree
+- **FDT**: Flattened Device Tree
+- **.its**: Image Tree Source
+- **.dtb**: Device Tree Blob
+
+References:
+
+- https://docs.u-boot.org/en/latest/usage/fit/index.html
+- https://fitspec.osfw.foundation/
+
+Design
+------
+
+The FIT-based approach, commonly adopted within the U-Boot community, offers a
+standardized solution for multi-DTB packaging. This design is the first
+implementation utilizing FIT to facilitate DT selection from a multi-DTB
+binary.
+
+FIT provides a flexible and extensible format to support multiple components
+(device tree, kernel image, ramdisk). It also supports multiple configurations
+so that the same FIT can be used to boot multiple platforms, with some
+components in common (e.g., kernel) and some specific to that platform (e.g.,
+device tree). The Flattened Image Tree Specification (FITSpec) suggests the
+image selection mechanism.
+
+Detailed Description
+^^^^^^^^^^^^^^^^^^^^
+
+1. In the FIT ITS file, each configuration comprises a compatible string along
+   with a declaration for the base DT blob and the overlays in sequence. A few
+   such configuration node examples are provided in the .its tree format below.
+
+2. This implementation uses a metadata binary structured in DT format for
+   selecting the appropriate configuration. A node, named
+   ``fdt-qcom-metadata.dtb``, for the metadata binary is provided under the
+   ``images`` node in the FIT tree with type ``qcom_metadata``.
+
+3. The compatible string suffixes in the FIT tree can be put in any order, but
+   the node corresponding to each suffix must be present in the
+   ``qcom-dtb-metadata`` binary. If any new suffix is introduced, it must be
+   added to the metadata (refer to ``qcom-dtb-metadata.dts`` below this
+   section). The new suffix sub-node must be added under the relevant node.
+
+   Suggested pattern::
+
+       <soc>-<soc-sku>-<socver>-<board>-<boardrev>-<board-subtype-peripheral-subtype>-<board-subtype-storage-type>-<board-subtype-memory-size>-<softsku>-<oem>
+
+4. Each of the suffixes inside the compatible string must be an exact match for
+   a DTB to be selected. Upon any mismatch, a configuration is rejected and the
+   search moves ahead with other available configurations.
+
+5. The compatible string that gets matched has its corresponding DTB(O)s
+   selected for boot.
+
+FIT ITS Configuration
+^^^^^^^^^^^^^^^^^^^^^
+
+Each configuration in the FIT ITS file comprises a compatible string along
+with a declaration for the base DT blob and overlays in sequence. Example::
+
+    config-1 {
+        compatible = "qcom,soc";
+        fdt = "fdt-soc-v2.dtb";
+    };
+
+    config-2 {
+        compatible = "qcom,soc-socv1.0";
+        fdt = "fdt-soc-v1.dtb";
+    };
+
+Refer: https://github.com/qualcomm-linux/qcom-dtb-metadata/blob/main/qcom-fitimage.its
+
+DTB Metadata Description and Parsing
+--------------------------------------
+
+The QCOM metadata supports the following DT nodes: ``soc``, ``soc-sku``,
+``socver``, ``board``, ``boardrev``, ``board-subtype-peripheral-subtype``,
+``board-subtype-storage-type``, ``board-subtype-memory-size``, ``softsku``
+and ``oem``. Sub-nodes of the respective type can be added under each node.
+
+The SoC specific identifiers are encapsulated in DT properties named
+``msm-id`` and ``socver-id``.
+
+Identifier Properties
+^^^^^^^^^^^^^^^^^^^^^
+
+- **msm-id** ``<u32>``: Each sub-node under the ``soc`` node must contain an
+  ``msm-id`` property. Bits 0-15 of the 32-bit value represent the chip
+  identifier; the remaining bits are reserved.
+
+  Each sub-node under the ``soc-sku`` node should contain an ``msm-id``
+  property. Bits 20-21 represent the package-id, bits 16-19 represent the
+  foundry-id; the remaining bits are ignored.
+
+- **socver-id** ``<u32>``: Each sub-node under the ``socver`` node should
+  contain a ``socver-id`` property. Bits 0-3 represent the chip minor version,
+  bits 4-7 represent the chip major version; the remaining bits are reserved.
+
+- **board-id** ``<u32>``: Each sub-node under the ``board`` node must contain
+  a ``board-id`` property. Bits 0-7 represent the board type; the remaining
+  bits are reserved.
+
+- **boardrev-id** ``<u32>``: Each sub-node under the ``boardrev`` node must
+  contain a ``boardrev-id`` property. Bits 0-3 represent the board minor
+  version, bits 4-7 represent the board major version; the remaining bits are
+  reserved.
+
+- **board-subtype** ``<u32>``: Each sub-node under the
+  ``board-subtype-peripheral-subtype``, ``board-subtype-storage-type`` and
+  ``board-subtype-memory-size`` nodes should contain a ``board-subtype``
+  property.
+
+  - Under ``board-subtype-peripheral-subtype``: bits 0-7 represent the
+    peripheral-based subtype; the remaining bits are ignored.
+  - Under ``board-subtype-storage-type``: bits 12-14 represent the storage
+    type; the remaining bits are ignored.
+  - Under ``board-subtype-memory-size``: bits 8-11 represent the memory size;
+    the remaining bits are ignored.
+
+- **oem-id** ``<u32>``: Each sub-node under the ``oem`` node must contain an
+  ``oem-id`` property. The ``oem-id`` represents the OEM and is added by the
+  OEM for selection of their board-specific DT.
+
+- **softsku-id** ``<u32>``: Each sub-node under the ``softsku`` node must
+  contain a ``softsku-id`` property. The ``softsku-id`` represents the software
+  SKU and is added for soft SKU (license) based selection of DT.
+
+The ``msm-id`` and ``socver-id`` are compared with the chip identifier value
+read from the SoC.
+
+The ``board-id``, ``boardrev-id``, ``board-subtype-peripheral-subtype`` and
+``oem-id`` are compared with the hardware description values (Configuration
+Data Table - CDT) flashed on the board's persistent memory.
+
+The ``board-subtype-storage-type`` is compared with the board's boot device
+type detected by U-Boot.
+
+The ``board-subtype-memory-size`` is compared with the board's DDR size
+detected by U-Boot.
+
+Refer: https://github.com/qualcomm-linux/qcom-dtb-metadata/blob/main/qcom-metadata.dts
+
+Guidelines for socver and boardrev
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- For any platform, the configuration entry with the shortest compatible string
+  (containing only the ``soc`` and ``board`` fields) must always reference the
+  latest hardware (SoC / board) version.
+
+- When adding support for a new hardware version that requires a separate DTB,
+  update the ``fdt`` property in the configuration with the shortest compatible
+  string so that it points to the DTB of the latest hardware version. If the
+  previously supported latest hardware version must continue to be used, add a
+  new ``socver``/``boardrev`` entry in the metadata DTS for the earlier
+  hardware. Additionally, add a new configuration entry in the FIT ITS that
+  corresponds to the platform compatible with the newly added
+  ``socver``/``boardrev``.
+
+- Consider the following example: The "soc" platform supports two chip versions
+  — socv1.0 and socv1.1 — and both versions share the same DTB (soc-v1.dtb).
+
+  FIT ITS::
+
+      config-1 {
+          compatible = "qcom,soc";
+          fdt = "fdt-soc-v1.dtb";
+      };
+
+  Now a new chip version socv2.0 is introduced, which requires a new DTB
+  (soc-v2.dtb). The older chip versions must continue to be supported.
+
+  Updated FIT ITS::
+
+      config-1 {
+          compatible = "qcom,soc";
+          fdt = "fdt-soc-v2.dtb";
+      };
+
+      config-2 {
+          compatible = "qcom,soc-socv1.0";
+          fdt = "fdt-soc-v1.dtb";
+      };
+
+      config-3 {
+          compatible = "qcom,soc-socv1.1";
+          fdt = "fdt-soc-v1.dtb";
+      };
+
+  Updated Metadata DTS::
+
+      socv1.0 {
+          socver-id = <0x10>;
+      };
+
+      socv1.1 {
+          socver-id = <0x11>;
+      };
+
+- If older hardware requires a separate DT and is not currently supported in
+  the FIT, add the required ``socver``/``boardrev`` entries in alphabetical
+  order.
+
+Image Building
+--------------
+
+FIT Image Properties
+^^^^^^^^^^^^^^^^^^^^
+
+- FIT is normally built with image data in the ``data`` property of each image
+  node. It is also possible for this data to reside outside the FIT itself
+  (external FIT). This allows the FDT part of the FIT to be quite small, so
+  that it can be loaded and scanned without loading a large amount of data.
+  Then when an image is needed it can be loaded from an external source.
+
+- External FITs use ``data-offset`` or ``data-position`` instead of ``data``.
+  The ``mkimage`` tool can convert a FIT to use external data using the ``-E``
+  argument.
+
+- The ``mkimage`` tool provides a ``-B`` argument to align each image to a
+  specific block size. Use ``-B 8`` to enforce 8-byte alignment.
+
+- The output FIT image must be named ``qclinux_fit.img`` so that U-Boot can
+  locate it in the FAT partition.
+
+Step-by-Step Workflow
+^^^^^^^^^^^^^^^^^^^^^
+
+1. **Install required tools**::
+
+       sudo apt-get install device-tree-compiler u-boot-tools mtools
+
+2. **Clone the qcom-dtb-metadata project**::
+
+       git clone https://github.com/qualcomm-linux/qcom-dtb-metadata.git
+       mkdir fit_image
+       cp -rap qcom-dtb-metadata/qcom-fitimage.its \
+               qcom-dtb-metadata/qcom-next-fitimage.its \
+               qcom-dtb-metadata/qcom-metadata.dts \
+               fit_image/
+
+3. **Copy compiled DTB/DTBO files from the kernel tree**
+
+   For steps on cloning and building the Qualcomm Linux Kernel Tree, refer to
+   https://github.com/qualcomm-linux/kmake-image/blob/main/README.md ::
+
+       mkdir -p fit_image/arch/arm64/boot/dts/qcom/
+       # Copy the compiled dtb/dtbo files from the kernel's kobj directory
+       cp -rap <u-boot build dir>/dts/upstream/src/arm64/qcom/*.dtb* \
+               fit_image/arch/arm64/boot/dts/qcom/
+
+4. **Compile the metadata DTS**::
+
+       cd fit_image
+       dtc -I dts -O dtb -o qcom-metadata.dtb qcom-metadata.dts
+
+5. **Generate the FIT image**
+
+   Use ``-E`` to place binary data outside the FIT structure and ``-B 8`` for
+   8-byte alignment::
+
+       mkdir out
+
+       # For kernel main branch
+       mkimage -f qcom-fitimage.its out/qclinux_fit.img -E -B 8
+
+       # For kernel qcom-next branch
+       mkimage -f qcom-next-fitimage.its out/qclinux_fit.img -E -B 8
+
+   The ``-E`` flag places binary data outside the FIT structure. However,
+   since ``/incbin/`` is used in the ``.its`` file, all binaries are appended
+   into the same image. The FIT structure contains the offset and size for each
+   appended binary.
+
+6. **Pack the FIT image into a FAT partition image using mkimage**
+
+   The ``mkimage`` tool supports creating FAT filesystem images directly via
+   the ``fatfs`` image type.
+
+       mkimage -T fatfs -d out/ fitimage.bin \
+           --fat-extra-space 512 \
+           --fat-volume-id "MYBOOT" \
+           --fat-mkfs-opts "-S 512 -a"
+
+   Available parameters:
+
+   - ``--fat-extra-space <KB>`` — extra padding in KB (default: 512 KB)
+   - ``--fat-type <12|16|32|0>`` — force FAT type (0 = auto-detect)
+   - ``--fat-volume-id <label>`` — volume label (default: ``BOOT``)
+   - ``--fat-mkfs-opts <opts>`` — extra ``mkfs.vfat`` options (default: ``-S 512``)
+
+   .. note::
+
+      This requires ``mkfs.vfat`` (from ``dosfstools``) and ``mcopy``
+      (from ``mtools``) to be installed on the build host.
+
+   The resulting ``fitimage.bin`` is a FAT partition image containing
+   ``qclinux_fit.img`` and is ready to be flashed to the ``dtb_a``
+   partition.
+
+7. **Flash the image**::
+
+       fastboot flash dtb_a fitimage.bin
+
+Boot Flow
+---------
+
+U-Boot reads ``qclinux_fit.img`` from the FAT partition image flashed to the
+``dtb_a`` partition. It uses the metadata binary and compatible strings in the
+FIT to select the correct DTB for the running hardware. The FIT image contains
+a configuration table FDT, metadata FDT, and DTB/DTBO binaries. The
+configuration table FDT contains the offset and size of each DTB/DTBO within
+the same buffer. U-Boot parses the metadata, matches the compatible strings
+against the hardware identifiers read from the SoC and CDT, and passes the
+selected DTB to the OS at boot time.
+
+Inspecting the Generated Image
+-------------------------------
+
+To verify the contents of the generated FIT image::
+
+    # Extract individual DTBs from the image
+    git clone https://github.com/PabloCastellano/extract-dtb.git
+    # Creates a "dtb/" folder containing each of the dtb/dtbo files
+    ./extract-dtb/extract_dtb/extract_dtb.py fitimage.bin
+
+    # Verify the ITS/FIT structure (configuration table FDT)
+    fdtdump dtb/01_dtbdump_*.dtb
+
+    # Verify the metadata DTB contents
+    fdtdump dtb/02_dtbdump_Image_with_compressed_metadata_blob.dtb
diff --git a/doc/mkimage.1 b/doc/mkimage.1
index 9a2d07cee75..ed6bd9f32d9 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -54,6 +54,14 @@ The new
 (Flattened Image Tree) format allows for more flexibility in handling images of
 various types and also enhances integrity protection of images with stronger
 checksums. It also supports verified boot.
+.P
+The
+.I fatfs
+image type creates a FAT filesystem image from a directory of files. The
+directory is specified with
+.BR \-d .
+The resulting image is a raw FAT partition image suitable for flashing directly
+to a storage device partition.
 .
 .SH OPTIONS
 .
@@ -227,6 +235,11 @@ then multiple images may be specified, separated by colons:
 .IP
 .IR image-data-file [\fB:\fP image-data-file .\|.\|.]
 .RE
+.IP
+For the
+.B fatfs
+image type, this argument specifies the input directory whose contents will be
+copied into the FAT filesystem image.
 .
 .TP
 .B \-x
@@ -496,6 +509,59 @@ using
 But if the original input to mkimage is a binary file (already compiled), then
 the timestamp is assumed to have been set previously.
 .
+.SS Options for creating FAT filesystem images
+.
+These options are only used when
+.B \-T fatfs
+is specified. The input directory is provided via
+.BR \-d .
+The host tools
+.B mkfs.vfat
+(from
+.IR dosfstools )
+and
+.B mcopy
+(from
+.IR mtools )
+must be installed on the build host.
+.
+.TP
+.BI \-\-fat\-extra\-space " size-kb"
+Add
+.I size-kb
+kilobytes of extra padding space to the FAT image beyond the size of the input
+data. This reserves room for future additions. The default is
+.BR 512 .
+.
+.TP
+.BI \-\-fat\-type " type"
+Force the FAT filesystem type to
+.IR type ,
+which must be one of
+.BR 12 ,
+.BR 16 ,
+.BR 32 ,
+or
+.B 0
+(auto-detect based on image size). The default is
+.B 0
+(auto-detect). FAT32 is automatically selected for images larger than 512 MB.
+.
+.TP
+.BI \-\-fat\-volume\-id " label"
+Set the FAT volume label to
+.IR label .
+The default is
+.BR BOOT .
+.
+.TP
+.BI \-\-fat\-mkfs\-opts " options"
+Pass additional options to
+.BR mkfs.vfat (8)
+when formatting the FAT image. The default is
+.BR "\-S 512"
+(512-byte sector size).
+.
 .SH CONFIGURATION
 This section documents the formats of the primary and secondary configuration
 options for each image type which supports them.
@@ -544,6 +610,21 @@ and valid
 are decimal numbers. See section 11.4.4.1 of the SAMA5D3 Series Data Sheet for
 valid values for each parameter.
 .
+.SS fatfs
+The
+.B fatfs
+image type creates a FAT filesystem image from a directory of files. The
+.B \-d
+option specifies the input directory; all files and subdirectories within it
+are copied into the FAT image using
+.BR mcopy .
+The image size is calculated automatically based on the total size of the input
+data plus the extra padding specified by
+.BR \-\-fat\-extra\-space .
+The FAT filesystem is formatted using
+.BR mkfs.vfat .
+No primary or secondary configuration is used.
+.
 .SS imximage
 The primary configuration is a file containing configuration commands, as
 documented in doc/\:imx/\:mkimage/\:imximage.txt of the U-Boot source.
@@ -903,10 +984,32 @@ of data storage.
 \fBmkimage -F external_data-offset.itb
 .EE
 .RE
+.P
+Create a FAT filesystem image from a directory, with default settings:
+.RS
+.P
+.EX
+\fBmkimage \-T fatfs \-d out/ fitimage.bin
+.EE
+.RE
+.P
+Create a FAT filesystem image with custom volume label, extra space, and
+mkfs.vfat options:
+.RS
+.P
+.EX
+\fBmkimage \-T fatfs \-d out/ fitimage.bin \\
+	\-\-fat\-extra\-space 512 \\
+	\-\-fat\-volume\-id "MYBOOT" \\
+	\-\-fat\-mkfs\-opts "\-S 512 \-a"
+.EE
+.RE
 .
 .SH SEE ALSO
 .BR dtc (1),
 .BR dumpimage (1),
+.BR mkfs.vfat (8),
+.BR mcopy (1),
 .BR openssl (1),
 the\~
 .UR https://\:u-boot\:.readthedocs\:.io/\:en/\:latest/\:index.html
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 7/7] mach-snapdragon: Reorder header includes
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
                   ` (5 preceding siblings ...)
  2026-04-17 12:09 ` [PATCH v3 6/7] doc: document mkimage fatfs type and Qualcomm multi-DTB Aswin Murugan
@ 2026-04-17 12:09 ` Aswin Murugan
  2026-04-20  4:06   ` Simon Glass
  2026-04-17 12:15 ` [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Jan Kiszka
  2026-04-20 18:11 ` Tom Rini
  8 siblings, 1 reply; 17+ messages in thread
From: Aswin Murugan @ 2026-04-17 12:09 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Rearrange the header include order for better readability and consistency.
No functional change intended.

Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
---
 arch/arm/mach-snapdragon/board.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
index 6a482ed186e..82bbbb8cba3 100644
--- a/arch/arm/mach-snapdragon/board.c
+++ b/arch/arm/mach-snapdragon/board.c
@@ -9,6 +9,16 @@
 #define LOG_CATEGORY LOGC_BOARD
 #define pr_fmt(fmt) "QCOM: " fmt
 
+#include <env.h>
+#include <fdt_support.h>
+#include <init.h>
+#include <lmb.h>
+#include <malloc.h>
+#include <power/regulator.h>
+#include <smem.h>
+#include <sort.h>
+#include <time.h>
+#include <usb.h>
 #include <asm/armv8/mmu.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
@@ -16,24 +26,13 @@
 #include <asm/system.h>
 #include <dm/device.h>
 #include <dm/pinctrl.h>
-#include <dm/uclass.h>
-#include <dm/uclass-internal.h>
 #include <dm/read.h>
-#include <power/regulator.h>
-#include <env.h>
-#include <fdt_support.h>
-#include <init.h>
+#include <dm/uclass-internal.h>
+#include <dm/uclass.h>
 #include <linux/arm-smccc.h>
 #include <linux/bug.h>
 #include <linux/psci.h>
 #include <linux/sizes.h>
-#include <lmb.h>
-#include <malloc.h>
-#include <fdt_support.h>
-#include <usb.h>
-#include <smem.h>
-#include <sort.h>
-#include <time.h>
 
 #include "qcom_fit_multidtb.h"
 #include "qcom-priv.h"
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
                   ` (6 preceding siblings ...)
  2026-04-17 12:09 ` [PATCH v3 7/7] mach-snapdragon: Reorder header includes Aswin Murugan
@ 2026-04-17 12:15 ` Jan Kiszka
  2026-04-20 18:11 ` Tom Rini
  8 siblings, 0 replies; 17+ messages in thread
From: Jan Kiszka @ 2026-04-17 12:15 UTC (permalink / raw)
  To: Aswin Murugan, trini, casey.connolly, neil.armstrong, sumit.garg,
	sughosh.ganu, ilias.apalodimas, gchan9527, mchitale, maximmosk4,
	jonas, marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, funderscore,
	hs, kory.maincent, jj251510319013, carlos.lopezr4096, u-boot-qcom,
	u-boot

On 17.04.26 14:09, Aswin Murugan wrote:
> This series adds dynamic device tree selection from FIT images for
> Qualcomm Snapdragon platforms, enabling U-Boot to select the
> appropriate DTB based on hardware parameters detected from SMEM.
> 
> Qualcomm fit based DTB format is documented in [1]
> The fit image contains only DTB, while the kernel will be part of UKI image.
> 

I suppose you know that UKIs (systemd-boot, EFI Boot Guard) provide DTB
selection as well. However, that is a fix-up for the case the firmware
does not provide a fitting DTB. This here is supposed to support the
firmware DTB delivery, correct?

Jan

-- 
Siemens AG, Foundational Technologies
Linux Expert Center

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 1/7] mach-snapdragon: Add generic SMEM cache infrastructure
  2026-04-17 12:09 ` [PATCH v3 1/7] mach-snapdragon: Add generic SMEM cache infrastructure Aswin Murugan
@ 2026-04-20  4:06   ` Simon Glass
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2026-04-20  4:06 UTC (permalink / raw)
  To: aswin.murugan
  Cc: trini, casey.connolly, neil.armstrong, sumit.garg, sughosh.ganu,
	ilias.apalodimas, gchan9527, mchitale, maximmosk4, jonas,
	marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Hi Aswin,

On 2026-04-17T12:09:44, Aswin Murugan <aswin.murugan@oss.qualcomm.com> wrote:
> mach-snapdragon: Add generic SMEM cache infrastructure
>
> Add cached access functions for commonly used SMEM data to reduce
> redundant SMEM lookups across the boot process.
>
> This patch introduces three generic caching functions:
> - qcom_get_smem_device(): Cached SMEM device access
> - qcom_get_socinfo(): Cached socinfo structure access
> - qcom_get_ram_partitions(): Cached RAM partition table access
>
> The implementation includes new header files for data structures:
> - include/soc/qcom/socinfo.h: Added socinfo header from Linux [1]
>   Provides socinfo structure definitions for SoC identification
>   and hardware parameters
> - arch/arm/mach-snapdragon/rampart.h: Provides RAM partition table
>   structures for memory layout information
>
> The caching mechanism initializes SMEM data on first access and
> returns cached pointers on subsequent calls, avoiding expensive
> SMEM lookups during boot. This infrastructure is designed to be
> [...]
>
> arch/arm/mach-snapdragon/board.c     |  95 +++++++++++++++
>  arch/arm/mach-snapdragon/qcom-priv.h |  24 ++++
>  arch/arm/mach-snapdragon/rampart.h   | 225 +++++++++++++++++++++++++++++++++++
>  include/soc/qcom/socinfo.h           | 114 ++++++++++++++++++
>  4 files changed, 458 insertions(+)

> diff --git a/arch/arm/mach-snapdragon/rampart.h b/arch/arm/mach-snapdragon/rampart.h
> @@ -0,0 +1,225 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * RAM partition table definitions
> + *
> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> + *
> + */
> +
> +#define SMEM_USABLE_RAM_PARTITION_TABLE              402

This header should have an include guard.

> diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
> @@ -749,3 +761,86 @@ void enable_caches(void)
> +/**
> + * qcom_get_smem_device() - Get cached SMEM device
> + *
> + * This function provides cached access to the SMEM device.
> + * On first call, it initializes the SMEM device.
> + * Subsequent calls return the cached pointer.
> + *
> + * Return: Pointer to SMEM device on success, NULL on failure
> + */
> +struct udevice *qcom_get_smem_device(void)
> +{
> +     struct udevice *dev;
> +
> +     if (uclass_first_device_err(UCLASS_SMEM, &dev)) {
> +             log_err("Failed to get SMEM device\n");
> +             return NULL;
> +     }
> +
> +     return dev;
> +}

Can you update the commit message and function documentation since
this does not cache anything.

Reviewed-by: Simon Glass <sjg@chromium.org>

Regards,
Simon

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 2/7] mach-snapdragon: Add FIT multi-DTB selection support
  2026-04-17 12:09 ` [PATCH v3 2/7] mach-snapdragon: Add FIT multi-DTB selection support Aswin Murugan
@ 2026-04-20  4:06   ` Simon Glass
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2026-04-20  4:06 UTC (permalink / raw)
  To: aswin.murugan
  Cc: trini, casey.connolly, neil.armstrong, sumit.garg, sughosh.ganu,
	ilias.apalodimas, gchan9527, mchitale, maximmosk4, jonas,
	marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Hi Aswin,

On 2026-04-17T12:09:44, Aswin Murugan <aswin.murugan@oss.qualcomm.com> wrote:
> mach-snapdragon: Add FIT multi-DTB selection support
>
> Implement multi DTB selection from FIT images based on hardware
> detection via SMEM.
>
> The implementation provides:
>
> 1. Hardware Detection: Reads SoC parameters from SMEM including chip ID,
>    version, platform ID, OEM variant, DDR size, and storage type from IMEM.
>
> 2. Metadata DTB Processing: Parses a metadata DTB (first image in FIT)
>    to build a "bucket list" of hardware-specific node names that match
>    the detected hardware parameters.
>
> 3. FIT Configuration Matching: Uses standard FIT mechanisms to find the
>    configuration with the most matching tokens in its compatible string
>    compared to the hardware-derived bucket list.
>
> 4. DTB Loading and Overlays: Loads the base DTB and applies any DTBOs
>    specified in the selected configuration using standard FIT overlay
> [...]
>
> arch/arm/mach-snapdragon/Kconfig             |    8 +
>  arch/arm/mach-snapdragon/Makefile            |    1 +
>  arch/arm/mach-snapdragon/board.c             |    7 +
>  arch/arm/mach-snapdragon/qcom_fit_multidtb.c | 1103 ++++++++++++++++++++++++++
>  arch/arm/mach-snapdragon/qcom_fit_multidtb.h |  189 +++++
>  5 files changed, 1308 insertions(+)

> diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
> @@ -585,6 +586,12 @@ int board_late_init(void)
> +     /* Try FIT multi-DTB selection if enabled */
> +     if (IS_ENABLED(CONFIG_QCOM_FIT_MULTIDTB)) {
> +             if (!qcom_fit_multidtb_setup())
> +                     log_debug("FIT multi-DTB selection not available or failed\n");
> +     }

The logic seems inverted, since qcom_fit_multidtb_setup() returns 0 on success.

> diff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.c b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c
> @@ -0,0 +1,1103 @@
> +#define TCSR_SOC_HW_VERSION        0x01fc8000

This address is hardcoded - does this mean the same TCSR base is used
on all SoCs?

> diff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.c b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c
> @@ -0,0 +1,1103 @@
> +     *ddr_type = 0;
> +     if (total_ddr_size <= DDR_128MB)
> +             *ddr_type = DDRTYPE_128MB;
> +     else if (total_ddr_size <= DDR_256MB)
> +             *ddr_type = DDRTYPE_256MB;
> +     else if (total_ddr_size <= DDR_512MB)
> +             *ddr_type = DDRTYPE_512MB;
> +     else if (total_ddr_size <= DDR_1024MB)
> +             *ddr_type = DDRTYPE_1024MB;
> +     else if (total_ddr_size <= DDR_2048MB)
> +             *ddr_type = DDRTYPE_2048MB;
> +     else if (total_ddr_size <= DDR_3072MB)
> +             *ddr_type = DDRTYPE_3072MB;
> +     else if (total_ddr_size <= DDR_4096MB)
> +             *ddr_type = DDRTYPE_4096MB;

If total_ddr_size > 4 GB, ddr_type remains 0. Is that intentional, or
should there be a final else clause for larger memory configurations?

> diff --git a/arch/arm/mach-snapdragon/qcom_fit_multidtb.c b/arch/arm/mach-snapdragon/qcom_fit_multidtb.c
> @@ -0,0 +1,1103 @@
> +     printf("DTB: %s\n", fdt_name);

Maybe use log_info() here for consistency with the rest of the file?

Reviewed-by: Simon Glass <sjg@chromium.org>

Regards,
Simon

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 3/7] configs: snapdragon: Enable FIT multi-DTB and configure IMEM
  2026-04-17 12:09 ` [PATCH v3 3/7] configs: snapdragon: Enable FIT multi-DTB and configure IMEM Aswin Murugan
@ 2026-04-20  4:06   ` Simon Glass
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2026-04-20  4:06 UTC (permalink / raw)
  To: aswin.murugan
  Cc: trini, casey.connolly, neil.armstrong, sumit.garg, sughosh.ganu,
	ilias.apalodimas, gchan9527, mchitale, maximmosk4, jonas,
	marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Hi Aswin,

On 2026-04-17T12:09:44, Aswin Murugan <aswin.murugan@oss.qualcomm.com> wrote:
> configs: snapdragon: Enable FIT multi-DTB and configure IMEM
>
> Enable CONFIG_QCOM_FIT_MULTIDTB by default for Qualcomm Snapdragon
> platforms to provide automatic DTB selection from qclinux_fit.img
> with overlay support.
>
> This allows U-Boot to automatically select the appropriate device
> tree based on hardware parameters detected from SMEM, improving
> boot compatibility across different hardware variants and reducing
> the need for board-specific DTB selection logic.
>
> Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
>
> configs/qcom_defconfig | 2 ++
>  1 file changed, 2 insertions(+)

> diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig
> @@ -12,6 +12,7 @@ CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
>  CONFIG_BUTTON_CMD=y
>  CONFIG_FIT=y
>  CONFIG_FIT_VERBOSE=y
> +CONFIG_QCOM_FIT_MULTIDTB=y

The subject says 'Enable FIT multi-DTB and configure IMEM' but this
patch does not configure IMEM

How about 'configs: snapdragon: Enable FIT multi-DTB support' ?

Reviewed-by: Simon Glass <sjg@chromium.org>

Regards,
Simon

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/7] image: add IH_TYPE_FATFS image type
  2026-04-17 12:09 ` [PATCH v3 4/7] image: add IH_TYPE_FATFS image type Aswin Murugan
@ 2026-04-20  4:06   ` Simon Glass
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2026-04-20  4:06 UTC (permalink / raw)
  To: aswin.murugan
  Cc: trini, casey.connolly, neil.armstrong, sumit.garg, sughosh.ganu,
	ilias.apalodimas, gchan9527, mchitale, maximmosk4, jonas,
	marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Hi Aswin,

On 2026-04-17T12:09:44, Aswin Murugan <aswin.murugan@oss.qualcomm.com> wrote:
> image: add IH_TYPE_FATFS image type
>
> Add a new image type IH_TYPE_FATFS to represent a raw FAT
> filesystem partition image. Register the type in the image
> type lookup table with short name "fatfs" and description
> "FAT Filesystem Image".
>
> Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
>
> boot/image.c    | 1 +
>  include/image.h | 1 +
>  2 files changed, 2 insertions(+)

> diff --git a/boot/image.c b/boot/image.c
> @@ -136,6 +136,7 @@ static const table_entry_t uimage_type[] = {
>       {       IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image",   },
>       {       IH_TYPE_FIRMWARE,   "firmware",   "Firmware",           },
>       {       IH_TYPE_FLATDT,     "flat_dt",    "Flat Device Tree",   },
> +     {       IH_TYPE_FATFS,      "fatfs",      "FAT Filesystem Image",       },

The uimage_type table is sorted alphabetically by short name. The
entry fatfs should come before filesystem (f-a-t < f-i-l), not after
flat_dt

Regards,
Simon

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 5/7] mkimage: add fatfs image type for FAT partition images
  2026-04-17 12:09 ` [PATCH v3 5/7] mkimage: add fatfs image type for FAT partition images Aswin Murugan
@ 2026-04-20  4:06   ` Simon Glass
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2026-04-20  4:06 UTC (permalink / raw)
  To: aswin.murugan
  Cc: trini, casey.connolly, neil.armstrong, sumit.garg, sughosh.ganu,
	ilias.apalodimas, gchan9527, mchitale, maximmosk4, jonas,
	marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Hi Aswin,

On 2026-04-17T12:09:44, Aswin Murugan <aswin.murugan@oss.qualcomm.com> wrote:
> mkimage: add fatfs image type for FAT partition images
>
> Add a new mkimage image type 'fatfs' that creates a raw FAT
> filesystem partition image from a directory of files.
>
> The image handler (fatimage.c) uses mkfs.vfat (dosfstools)
> to format the image and mcopy (mtools) to populate it. The
> image size is calculated automatically from the input
> directory size plus FAT metadata overhead.
>
> New long options added to mkimage:
>   --fat-extra-space <KB>  extra padding (default: 512 KB)
>   --fat-type <0|12|16|32> FAT type (0 = auto-detect)
>   --fat-volume-id <label> volume label (default: BOOT)
>   --fat-mkfs-opts <opts>  extra mkfs.vfat options
>
> Usage:
>   mkimage -T fatfs -d <input-dir> \
>       --fat-extra-space 512 \
>       --fat-volume-id "MYBOOT" \
> [...]
>
> tools/Makefile   |   1 +
>  tools/fatimage.c | 495 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  tools/fatimage.h |  25 +++
>  tools/mkimage.c  |  21 +++
>  tools/mkimage.h  |  15 ++
>  5 files changed, 557 insertions(+)

> diff --git a/tools/mkimage.c b/tools/mkimage.c
> @@ -204,6 +204,10 @@ static const struct option longopts[] = {
> +{ "fat-extra-space", required_argument, NULL, OPT_FAT_EXTRA },
> +     { "fat-type", required_argument, NULL, OPT_FAT_TYPE },

The first line is missing its leading tab.

> diff --git a/tools/fatimage.c b/tools/fatimage.c
> @@ -0,0 +1,495 @@
> +static int fatimage_set_header(void *ptr, struct stat *sbuf, int ifd,
> +                            struct image_tool_params *params)

The set_header callback in struct image_type_params returns void, not int

Assuming you don't want to update that (which you might?), please
change the return type to void and call exit() on unrecoverable
errors, like the other image handlers.

> diff --git a/tools/fatimage.c b/tools/fatimage.c
> @@ -0,0 +1,495 @@
> +static int fatimage_check_params(struct image_tool_params *params)
> +{
> +     if (!fatparams.input_dir) {
> +             fprintf(stderr, "Error: Input directory not specified\n");
> +             fprintf(stderr, "Use -d <directory> to specify input directory\n");
> +             return -1;
> +     }
> +
> +     struct stat st;
> +     if (stat(fatparams.input_dir, &st) < 0) {

Please move the decl to the start to the top of the function.

> diff --git a/tools/fatimage.c b/tools/fatimage.c
> @@ -0,0 +1,495 @@
> +void fatimage_set_dir(const char *dir)
> +{
> +     fatparams.input_dir = strdup(dir);
> +}
> +
> +void fatimage_set_extra_space(int space_kb)
> +{
> +     fatparams.extra_space = space_kb;
> +}
> +
> +void fatimage_set_fat_type(int type)
> +{
> +     fatparams.fat_type = type;
> +}
> +
> +void fatimage_set_volume_id(const char *volid)
> +{
> +     fatparams.volume_id = strdup(volid);
> +}
> +
> +void fatimage_set_mkfs_opts(const char *opts)
> +{
> +     fatparams.mkfs_opts = strdup(opts);
> +}

The strdup() calls in fatimage_set_dir(), fatimage_set_volume_id() and
fatimage_set_mkfs_opts() can return NULL, but the return value is not
checked. Please check for NULL and handle the error.

Regards,
Simon

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 6/7] doc: document mkimage fatfs type and Qualcomm multi-DTB
  2026-04-17 12:09 ` [PATCH v3 6/7] doc: document mkimage fatfs type and Qualcomm multi-DTB Aswin Murugan
@ 2026-04-20  4:06   ` Simon Glass
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2026-04-20  4:06 UTC (permalink / raw)
  To: aswin.murugan
  Cc: trini, casey.connolly, neil.armstrong, sumit.garg, sughosh.ganu,
	ilias.apalodimas, gchan9527, mchitale, maximmosk4, jonas,
	marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

Hi Aswin,

On 2026-04-17T12:09:44, Aswin Murugan <aswin.murugan@oss.qualcomm.com> wrote:
> doc: document mkimage fatfs type and Qualcomm multi-DTB
>
> Update doc/mkimage.1 to document the new fatfs image type,
> the --fat-* long options, a fatfs entry in the CONFIGURATION
> section, and two usage examples.
>
> Add doc/board/qualcomm/multi_dtb.rst describing the
> Qualcomm FIT-based multi-DTB packaging workflow for
> Snapdragon platforms. The document covers:
> - FIT ITS configuration and compatible string matching
> - QCOM metadata binary format and identifier properties
> - Guidelines for adding new socver/boardrev entries
> - Step-by-step image creation using mkimage -T fatfs
>
> Update doc/board/qualcomm/index.rst to include the new
> multi_dtb page in the toctree.
>
> Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
>
> doc/board/qualcomm/index.rst     |   1 +
>  doc/board/qualcomm/multi_dtb.rst | 352 +++++++++++++++++++++++++++++++++++++++
>  doc/mkimage.1                    | 103 ++++++++++++
>  3 files changed, 456 insertions(+)

> diff --git a/doc/board/qualcomm/multi_dtb.rst b/doc/board/qualcomm/multi_dtb.rst
> @@ -0,0 +1,352 @@
> +       cp -rap <u-boot build dir>/dts/upstream/src/arm64/qcom/*.dtb* \
> +               fit_image/arch/arm64/boot/dts/qcom/

The text above refers to "Qualcomm Linux Kernel Tree" but the
placeholder says "u-boot build dir". Please change this to reference
the kernel build directory.

> diff --git a/doc/board/qualcomm/multi_dtb.rst b/doc/board/qualcomm/multi_dtb.rst
> @@ -0,0 +1,352 @@
> +1. **Install required tools**::
> +
> +       sudo apt-get install device-tree-compiler u-boot-tools mtools

Step 6 notes that dosfstools is also required for mkfs.vfat - please
add dosfstools to this install command.

> diff --git a/doc/board/qualcomm/multi_dtb.rst b/doc/board/qualcomm/multi_dtb.rst
> @@ -0,0 +1,352 @@
> +6. **Pack the FIT image into a FAT partition image using mkimage**
> +
> +   The `mkimage tool supports creating FAT filesystem images directly via
> +   the fatfs image type.
> +
> +       mkimage -T fatfs -d out/ fitimage.bin \

This code block is missing the RST literal-block marker, i.e. the text
before it should end with ::

> diff --git a/doc/mkimage.1 b/doc/mkimage.1
> @@ -903,10 +984,32 @@ of data storage.
> +.BR mkfs.vfat (8),
> +.BR mcopy (1),

The SEE ALSO entries should be in alphabetical order. Please swap
these two lines so mcopy comes before mkfs.vfat

Regards,
Simon

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 7/7] mach-snapdragon: Reorder header includes
  2026-04-17 12:09 ` [PATCH v3 7/7] mach-snapdragon: Reorder header includes Aswin Murugan
@ 2026-04-20  4:06   ` Simon Glass
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2026-04-20  4:06 UTC (permalink / raw)
  To: aswin.murugan
  Cc: trini, casey.connolly, neil.armstrong, sumit.garg, sughosh.ganu,
	ilias.apalodimas, gchan9527, mchitale, maximmosk4, jonas,
	marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

On 2026-04-17T12:09:44, Aswin Murugan <aswin.murugan@oss.qualcomm.com> wrote:
> mach-snapdragon: Reorder header includes
>
> Rearrange the header include order for better readability and consistency.
> No functional change intended.
>
> Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
>
> arch/arm/mach-snapdragon/board.c | 25 ++++++++++++-------------
>  1 file changed, 12 insertions(+), 13 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms
  2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
                   ` (7 preceding siblings ...)
  2026-04-17 12:15 ` [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Jan Kiszka
@ 2026-04-20 18:11 ` Tom Rini
  8 siblings, 0 replies; 17+ messages in thread
From: Tom Rini @ 2026-04-20 18:11 UTC (permalink / raw)
  To: Aswin Murugan
  Cc: casey.connolly, neil.armstrong, sumit.garg, sughosh.ganu,
	ilias.apalodimas, gchan9527, mchitale, maximmosk4, jonas,
	marek.vasut, quentin.schulz, peng.fan, sajattack,
	balaji.selvanathan, wolfgang.wallner, e, yangshiji66, jan.kiszka,
	funderscore, hs, kory.maincent, jj251510319013, carlos.lopezr4096,
	u-boot-qcom, u-boot

[-- Attachment #1: Type: text/plain, Size: 1260 bytes --]

On Fri, Apr 17, 2026 at 05:39:44PM +0530, Aswin Murugan wrote:
> This series adds dynamic device tree selection from FIT images for
> Qualcomm Snapdragon platforms, enabling U-Boot to select the
> appropriate DTB based on hardware parameters detected from SMEM.
> 
> Qualcomm fit based DTB format is documented in [1]
> The fit image contains only DTB, while the kernel will be part of UKI image.
> 
> The implementation consists of three parts:
> 
> 1. SMEM cache infrastructure: Provides cached access to commonly
>    used SMEM data (socinfo, RAM partitions) to avoid redundant
>    lookups during boot. Includes socinfo header from Linux kernel
>    for SoC identification.
> 
> 2. FIT multi-DTB selection: Implements the core selection logic
>    that reads hardware parameters from SMEM, parses metadata DTB,
>    matches FIT configurations, and loads the selected DTB with
>    overlays. Integrates with EFI boot flow by setting fdt_addr.
> 
> 3. mkimage: add fatfs image type for FAT partition images
>    Added fatimage.c handler that uses mkfs.vfat and mcopy to create
>    FAT images from a directory.

I'm unsure why part 3 here is appropriate for U-Boot. It's wrapping
existing tooling to create a fat image?

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-04-20 18:12 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-17 12:09 [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Aswin Murugan
2026-04-17 12:09 ` [PATCH v3 1/7] mach-snapdragon: Add generic SMEM cache infrastructure Aswin Murugan
2026-04-20  4:06   ` Simon Glass
2026-04-17 12:09 ` [PATCH v3 2/7] mach-snapdragon: Add FIT multi-DTB selection support Aswin Murugan
2026-04-20  4:06   ` Simon Glass
2026-04-17 12:09 ` [PATCH v3 3/7] configs: snapdragon: Enable FIT multi-DTB and configure IMEM Aswin Murugan
2026-04-20  4:06   ` Simon Glass
2026-04-17 12:09 ` [PATCH v3 4/7] image: add IH_TYPE_FATFS image type Aswin Murugan
2026-04-20  4:06   ` Simon Glass
2026-04-17 12:09 ` [PATCH v3 5/7] mkimage: add fatfs image type for FAT partition images Aswin Murugan
2026-04-20  4:06   ` Simon Glass
2026-04-17 12:09 ` [PATCH v3 6/7] doc: document mkimage fatfs type and Qualcomm multi-DTB Aswin Murugan
2026-04-20  4:06   ` Simon Glass
2026-04-17 12:09 ` [PATCH v3 7/7] mach-snapdragon: Reorder header includes Aswin Murugan
2026-04-20  4:06   ` Simon Glass
2026-04-17 12:15 ` [PATCH v3 0/7] Add FIT multi-DTB selection for Qualcomm platforms Jan Kiszka
2026-04-20 18:11 ` Tom Rini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox