[PATCH v2 03/10] spl: ufs: add Falcon mode load path

Alexey Charkov <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.