In Falcon mode, the SPL loads a FIT image containing a Linux kernel
instead of U-boot proper, and it may need to fall back to loading U-boot
if Linux is unavailable.

Add support for images containing a Linux kernel, optionally on a
different UFS LUN and/or offset vs. U-boot proper to enable fallback.

Signed-off-by: Alexey Charkov <[email protected]>
---
 common/spl/Kconfig   | 23 +++++++++++++++++++++
 common/spl/spl_ufs.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 7c639ed8f763..0e0c60eb9793 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1653,6 +1653,16 @@ config SPL_UFS_RAW_U_BOOT_DEVNUM
          SCSI device number, which might differ from the UFS LUN if you have
          multiple SCSI devices attached and recognized by the SPL.
 
+config SPL_UFS_RAW_OS_DEVNUM
+       int "Falcon mode: SCSI device number of the UFS device to load OS from"
+       depends on SPL_UFS_SUPPORT && SPL_OS_BOOT
+       default SPL_UFS_RAW_U_BOOT_DEVNUM
+       help
+         UFS devices are usually configured with multiple LUNs, which present
+         themselves as sequentially numbered SCSI devices. This option controls
+         which of them SPL will attempt to load a Falcon OS payload from.
+         It allows putting Linux FITs on a different UFS LU than U-Boot.
+
 config SPL_UFS_RAW_U_BOOT_SECTOR
        hex "Address on the UFS to load U-Boot from"
        depends on SPL_UFS_SUPPORT
@@ -1661,6 +1671,19 @@ config SPL_UFS_RAW_U_BOOT_SECTOR
          Address on the block device to load U-Boot from.
          Units: UFS sectors (1 sector = 4096 bytes).
 
+config SPL_UFS_RAW_OS_SECTOR
+       hex "Falcon mode: address on the UFS to load OS image from"
+       depends on SPL_UFS_SUPPORT && SPL_OS_BOOT
+       default SPL_UFS_RAW_U_BOOT_SECTOR
+       help
+         Address on the block device to load a Falcon OS FIT/image from.
+         Units: UFS sectors (1 sector = 4096 bytes).
+
+         The default shares the region with U-Boot, which suits Falcon-only
+         boot: the OS image is written where U-Boot would have gone, so only
+         one region has to be reserved and there is no fallback. Point this
+         at a separate location to keep a working U-Boot to fall back to.
+
 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 cef1843f40f3..d35b5e7ad33a 100644
--- a/common/spl/spl_ufs.c
+++ b/common/spl/spl_ufs.c
@@ -20,13 +20,38 @@ 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_raw_os(struct spl_image_info *spl_image,
+                                    struct spl_boot_device *bootdev,
+                                    struct spl_load_info *load,
+                                    struct blk_desc *bd)
+{
+       ulong sector = config_opt_enabled(CONFIG_SPL_OS_BOOT,
+                                         CONFIG_SPL_UFS_RAW_OS_SECTOR,
+                                         CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR);
+       int err;
+
+       err = spl_load(spl_image, bootdev, load, 0,
+                      sector << bd->log2blksz);
+       if (err)
+               return err;
+
+       if (spl_image->os != IH_OS_LINUX && spl_image->os != IH_OS_TEE &&
+           spl_image->os != IH_OS_ARM_TRUSTED_FIRMWARE) {
+               puts("Expected OS image is not found\n");
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
 static int spl_ufs_load_image(struct spl_image_info *spl_image,
                              struct spl_boot_device *bootdev)
 {
        unsigned long sector = CONFIG_SPL_UFS_RAW_U_BOOT_SECTOR;
+       struct spl_load_info load, os_load;
+       struct blk_desc *bd, *os_bd;
        int devnum = CONFIG_SPL_UFS_RAW_U_BOOT_DEVNUM;
-       struct spl_load_info load;
-       struct blk_desc *bd;
+       int os_devnum;
        int err;
 
        /* try to recognize storage devices immediately */
@@ -36,6 +61,35 @@ static int spl_ufs_load_image(struct spl_image_info 
*spl_image,
                return -ENODEV;
 
        spl_load_init(&load, spl_ufs_load_read, bd, bd->blksz);
+       if (CONFIG_IS_ENABLED(OS_BOOT) && spl_falcon_boot()) {
+               os_devnum = config_opt_enabled(CONFIG_SPL_OS_BOOT,
+                                              CONFIG_SPL_UFS_RAW_OS_DEVNUM,
+                                              
CONFIG_SPL_UFS_RAW_U_BOOT_DEVNUM);
+               if (os_devnum == devnum) {
+                       os_bd = bd;
+                       os_load = load;
+               } else {
+                       os_bd = blk_get_devnum_by_uclass_id(UCLASS_SCSI, 
os_devnum);
+                       if (!os_bd) {
+                               puts("spl_ufs_load_image: UFS OS device not 
found\n");
+                               if (CONFIG_IS_ENABLED(OS_BOOT_SECURE))
+                                       return -ENODEV;
+                               goto load_uboot;
+                       }
+                       spl_load_init(&os_load, spl_ufs_load_read, os_bd, 
os_bd->blksz);
+               }
+
+               err = spl_ufs_load_image_raw_os(spl_image, bootdev, &os_load, 
os_bd);
+               if (!err)
+                       return 0;
+
+               puts("spl_ufs_load_image: Failed to load falcon payload\n");
+               log_debug("(error=%d)\n", err);
+               if (CONFIG_IS_ENABLED(OS_BOOT_SECURE))
+                       return err;
+       }
+
+load_uboot:
        err = spl_load(spl_image, bootdev, &load, 0, sector << bd->log2blksz);
        if (err) {
                puts("spl_ufs_load_image: ufs block read error\n");

-- 
2.54.0

Reply via email to