[PATCH 1/4] spl: ufs: Add partition support and flexible loading

Balaji Selvanathan balaji.selvanathan at oss.qualcomm.com
Thu Apr 9 16:43:31 CEST 2026


Add partition-based loading support to SPL UFS, similar to the
existing implementation in spl_mmc.c. This allows loading from
named partitions or partition numbers instead of hardcoded sector
offsets.

The loading strategy tries methods in order: absolute sector if
configured, partition by name, partition by number, then filesystem
mode (placeholder for future implementation).

This brings UFS boot flexibility on par with MMC/SD boot.

Signed-off-by: Balaji Selvanathan <balaji.selvanathan at oss.qualcomm.com>
---
 common/spl/Kconfig   |  40 ++++++++++-
 common/spl/spl_ufs.c | 188 +++++++++++++++++++++++++++++++++++++++++++++------
 include/part.h       |   3 +-
 include/spl.h        |   4 ++
 4 files changed, 214 insertions(+), 21 deletions(-)

diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index a21b71ad5d1..b3c7a1d8aa3 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1637,9 +1637,47 @@ config SPL_UFS_RAW_U_BOOT_SECTOR
 	depends on SPL_UFS_SUPPORT
 	default 0x800 if ARCH_ROCKCHIP
 	help
-	  Address on the block device to load U-Boot from.
+	  Absolute sector offset on the UFS LUN to load U-Boot from.
+	  This is tried first before partition-based loading.
+	  Set to 0x0 to skip absolute sector loading and use partition mode.
 	  Units: UFS sectors (1 sector = 4096 bytes).
 
+config SPL_UFS_RAW_U_BOOT_USE_PARTITION
+	bool "Enable UFS partition support for raw mode"
+	depends on SPL_UFS_SUPPORT
+	select SPL_LIBDISK_SUPPORT
+	help
+	  Enable support for loading from a specific partition on UFS
+	  in raw mode. When enabled, you can specify either a partition
+	  name or partition number to load from.
+
+config SPL_UFS_RAW_U_BOOT_PARTITION_NAME
+	string "Partition name to load U-Boot from"
+	depends on SPL_UFS_RAW_U_BOOT_USE_PARTITION
+	help
+	  Name of the partition to load U-Boot from in UFS raw mode.
+	  This is tried before partition number lookup.
+	  Leave empty to skip name-based lookup.
+	  Example: "boot", "uefi", "dtb_a"
+
+config SPL_UFS_RAW_U_BOOT_PARTITION_NUM
+	int "Partition number to load U-Boot from"
+	depends on SPL_UFS_RAW_U_BOOT_USE_PARTITION
+	help
+	  Partition number to load U-Boot from when using UFS raw mode
+	  with partition support. This is used if partition name is not
+	  specified or not found.
+
+config SPL_UFS_FS
+	bool "Enable UFS filesystem boot mode"
+	depends on SPL_UFS_SUPPORT
+	help
+	  Enable filesystem-based boot from UFS. This allows loading
+	  U-Boot from FAT or EXT4 filesystems on UFS partitions.
+	  This is tried as a fallback if raw mode loading fails.
+
+	  Note: Filesystem support is not yet fully implemented.
+
 config SPL_WATCHDOG
 	bool "Support watchdog drivers"
 	imply SPL_WDT if !HW_WATCHDOG
diff --git a/common/spl/spl_ufs.c b/common/spl/spl_ufs.c
index cef1843f40f..c4e793bf701 100644
--- a/common/spl/spl_ufs.c
+++ b/common/spl/spl_ufs.c
@@ -3,15 +3,19 @@
  * (C) Copyright 2025 Alexey Charkov <alchark at gmail.com>
  */
 
+#include <dm.h>
+#include <log.h>
 #include <spl.h>
 #include <spl_load.h>
 #include <scsi.h>
-#include <errno.h>
-#include <image.h>
+#include <part.h>
+#include <blk.h>
 #include <linux/compiler.h>
-#include <log.h>
+#include <errno.h>
 
-static ulong spl_ufs_load_read(struct spl_load_info *load, ulong off, ulong size, void *buf)
+/* Block read callback for spl_load framework */
+static ulong h_spl_ufs_load_read(struct spl_load_info *load, ulong off,
+				 ulong size, void *buf)
 {
 	struct blk_desc *bd = load->priv;
 	lbaint_t sector = off >> bd->log2blksz;
@@ -20,30 +24,176 @@ static ulong spl_ufs_load_read(struct spl_load_info *load, ulong off, ulong size
 	return blk_dread(bd, sector, count, buf) << bd->log2blksz;
 }
 
-static int spl_ufs_load_image(struct spl_image_info *spl_image,
-			      struct spl_boot_device *bootdev)
+/* Load image from raw sector */
+static int ufs_load_image_raw_sector(struct spl_image_info *spl_image,
+				     struct spl_boot_device *bootdev,
+				     struct blk_desc *bd,
+				     unsigned long sector)
 {
-	unsigned long sector = CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR;
-	int devnum = CONFIG_SPL_UFS_RAW_U_BOOT_DEVNUM;
 	struct spl_load_info load;
+	int ret;
+
+	debug("spl: ufs loading from sector 0x%lx\n", sector);
+
+	spl_load_init(&load, h_spl_ufs_load_read, bd, bd->blksz);
+	ret = spl_load(spl_image, bootdev, &load, 0, sector << bd->log2blksz);
+
+	if (ret) {
+		debug("spl: ufs load failed: %d\n", ret);
+		return ret;
+	}
+
+	debug("spl: ufs load successful\n");
+	return 0;
+}
+
+u32 __weak spl_ufs_boot_mode(const u32 boot_device)
+{
+	return UFS_MODE_RAW;
+}
+
+int spl_ufs_load(struct spl_image_info *spl_image,
+		 struct spl_boot_device *bootdev,
+		 const char *filename)
+{
+	u32 boot_mode;
+	int ret = 0;
+	int devnum = CONFIG_SPL_UFS_RAW_U_BOOT_DEVNUM;
 	struct blk_desc *bd;
-	int err;
+	unsigned long sector = 0;
+
+	log_debug("spl: ufs devnum=%d\n", devnum);
+
+	ret = scsi_scan(false);
+	if (ret) {
+		printf("spl: scsi scan failed: %d\n", ret);
+		return ret;
+	}
 
-	/* try to recognize storage devices immediately */
-	scsi_scan(false);
 	bd = blk_get_devnum_by_uclass_id(UCLASS_SCSI, devnum);
-	if (!bd)
+	if (!bd) {
+		printf("spl: could not get UFS device %d\n", devnum);
 		return -ENODEV;
+	}
 
-	spl_load_init(&load, spl_ufs_load_read, bd, bd->blksz);
-	err = spl_load(spl_image, bootdev, &load, 0, sector << bd->log2blksz);
-	if (err) {
-		puts("spl_ufs_load_image: ufs block read error\n");
-		log_debug("(error=%d)\n", err);
-		return err;
+	boot_mode = spl_ufs_boot_mode(bootdev->boot_device);
+
+	switch (boot_mode) {
+	case UFS_MODE_RAW:
+		debug("spl: ufs raw mode\n");
+
+		/* Step 1: Try absolute sector (if configured and non-zero) */
+#ifdef CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR
+		if (CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR != 0) {
+			debug("spl: trying absolute sector 0x%x\n",
+			      CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR);
+
+			ret = ufs_load_image_raw_sector(spl_image, bootdev, bd,
+							CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR);
+
+			if (!ret) {
+				debug("spl: loaded from absolute sector\n");
+				return 0;
+			}
+			debug("spl: absolute sector failed: %d\n", ret);
+		}
+#endif
+
+		/* Step 2-4: Try partition-based loading */
+#ifdef CONFIG_SPL_UFS_RAW_U_BOOT_USE_PARTITION
+		{
+			struct disk_partition part_info;
+			int part_found = 0;
+
+			/* Step 2: Try partition name (if configured) */
+#ifdef CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NAME
+			if (strlen(CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NAME) > 0) {
+				debug("spl: trying partition name '%s'\n",
+				      CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NAME);
+
+				ret = part_get_info_by_name(bd,
+							    CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NAME,
+					&part_info);
+
+				if (ret >= 0) {
+					debug("spl: found partition '%s' at 0x%lx\n",
+					      CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NAME,
+					      (ulong)part_info.start);
+					sector = part_info.start;
+					part_found = 1;
+				} else {
+					debug("spl: partition name not found: %d\n", ret);
+				}
+			}
+#endif
+
+			/* Step 3: Try partition number (if name not found) */
+#ifdef CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NUM
+			if (!part_found) {
+				debug("spl: trying partition number %d\n",
+				      CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NUM);
+
+				ret = part_get_info(bd,
+						    CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NUM,
+						    &part_info);
+
+				if (ret >= 0) {
+					debug("spl: found partition %d at 0x%lx\n",
+					      CONFIG_SPL_UFS_RAW_U_BOOT_PARTITION_NUM,
+					      (ulong)part_info.start);
+					sector = part_info.start;
+					part_found = 1;
+				} else {
+					debug("spl: partition number not found: %d\n", ret);
+				}
+			}
+#endif
+
+			/* Load from partition if found */
+			if (part_found) {
+				ret = ufs_load_image_raw_sector(spl_image, bootdev, bd, sector);
+
+				if (!ret) {
+					debug("spl: loaded from partition\n");
+					return 0;
+				}
+				debug("spl: partition load failed: %d\n", ret);
+			}
+		}
+#endif /* CONFIG_SPL_UFS_RAW_U_BOOT_USE_PARTITION */
+
+		/* Step 4: Fall through to FS mode if enabled */
+		debug("spl: raw mode failed, trying fs\n");
+		fallthrough;
+
+#ifdef CONFIG_SPL_UFS_FS
+	case UFS_MODE_FS:
+		debug("spl: ufs fs mode\n");
+
+		/* TODO: Implement filesystem support */
+		printf("spl: ufs filesystem boot not implemented\n");
+		ret = -ENOSYS;
+		break;
+#endif
+
+	default:
+		puts("spl: ufs: invalid boot mode\n");
+		ret = -EINVAL;
 	}
 
-	return 0;
+	return ret;
+}
+
+/* SPL load image entry point */
+static int spl_ufs_load_image(struct spl_image_info *spl_image,
+			      struct spl_boot_device *bootdev)
+{
+	return spl_ufs_load(spl_image, bootdev,
+#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
+			    CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
+#else
+			    NULL);
+#endif
 }
 
 SPL_LOAD_IMAGE_METHOD("UFS", 0, BOOT_DEVICE_UFS, spl_ufs_load_image);
diff --git a/include/part.h b/include/part.h
index 15daacd7faa..47b91e2043c 100644
--- a/include/part.h
+++ b/include/part.h
@@ -463,7 +463,8 @@ ulong disk_blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt);
 # if defined(CONFIG_SPL_FS_EXT4) || defined(CONFIG_SPL_FS_FAT) || \
 	defined(CONFIG_SPL_FS_SQUASHFS) || \
 	defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION) || \
-	defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE)
+	defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION_TYPE) || \
+	defined(CONFIG_SPL_UFS_RAW_U_BOOT_USE_PARTITION)
 #  define part_get_info_ptr(x)	x
 # else
 #  define part_get_info_ptr(x)	NULL
diff --git a/include/spl.h b/include/spl.h
index 5078d7525ab..a617bc26c04 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -29,6 +29,10 @@ struct legacy_img_hdr;
 #define MMCSD_MODE_FS		2
 #define MMCSD_MODE_EMMCBOOT	3
 
+/* UFS boot modes */
+#define UFS_MODE_RAW		1
+#define UFS_MODE_FS		2
+
 struct blk_desc;
 struct legacy_img_hdr;
 struct spl_boot_device;

-- 
2.34.1



More information about the U-Boot mailing list