[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