[PATCH v3 7/8] board: ti: j721e: During resume spl notify tf-a that the board is resuming

Thomas Richard thomas.richard at bootlin.com
Mon Jan 8 17:56:27 CET 2024


During the boot a copy of DM-Firmware and TF-A is done in a reserved memory
area.
When resuming, R5 SPL uses these copies instead of the fit image.
R5 SPL writes a magic value in the scratchpad ram to notify TF-A that
the board is resuming.

Based on the work of Gregory CLEMENT <gregory.clement at bootlin.com>

Signed-off-by: Thomas Richard <thomas.richard at bootlin.com>
Signed-off-by: Gregory CLEMENT <gregory.clement at bootlin.com>

---

Changes in v3:
- At resume, R5 SPL doesn't restore TF-A anymore.
  TF-A is started like during a cold boot. R5 SPL will notify that the board is
  resuming using a magic value written in the scratchpad ram.
  TF-A will restore itself.

Changes in v2:
- Check if TF-A is running in DRAM, if yes no need to restore it
- Remove BL31_START macro, and get TF-A start address from the fit image

 arch/arm/mach-k3/common.c                     | 65 ++++++++++++++++++-
 .../arm/mach-k3/include/mach/j721e_hardware.h |  1 +
 arch/arm/mach-k3/include/mach/j721e_spl.h     | 30 +++++++++
 arch/arm/mach-k3/sysfw-loader.c               |  9 ++-
 4 files changed, 101 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index a35110429b..546ea3cf5e 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -26,6 +26,7 @@
 #include <env.h>
 #include <elf.h>
 #include <soc.h>
+#include <hang.h>
 
 #if IS_ENABLED(CONFIG_SYS_K3_SPL_ATF)
 enum {
@@ -221,6 +222,11 @@ void release_resources_for_core_shutdown(void)
 	}
 }
 
+__weak int board_is_resuming(void)
+{
+	return 0;
+}
+
 void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
 {
 	typedef void __noreturn (*image_entry_noargs_t)(void);
@@ -235,6 +241,35 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
 	if (ret)
 		panic("rproc failed to be initialized (%d)\n", ret);
 
+	if (board_is_resuming()) {
+#if IS_ENABLED(CONFIG_SOC_K3_J721E)
+		if (!valid_elf_image(LPM_DM))
+			panic("%s: DM-Firmware image is not valid, it cannot be loaded\n",
+			      __func__);
+
+		loadaddr = load_elf_image_phdr(LPM_DM);
+
+		memcpy((void *)*(ulong *)(LPM_BL31_START),
+		       (void *)LPM_BL31, *(ulong *)(LPM_BL31_SIZE));
+
+		ret = rproc_load(1, *(ulong *)(LPM_BL31_START), 0x200);
+		if (ret)
+			panic("%s: ATF failed to load on rproc (%d)\n", __func__, ret);
+
+#if (CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS) && IS_ENABLED(CONFIG_SYS_K3_SPL_ATF))
+		debug("%s: Authenticating image: addr=%lx, size=%ld, os=%s\n", __func__,
+		      *(ulong *)(LPM_BL31_START), *(ulong *)(LPM_BL31_SIZE),
+		      image_os_match[IMAGE_ID_ATF]);
+
+		ti_secure_image_post_process((void *)LPM_BL31_START,
+					     (size_t *)LPM_BL31_SIZE);
+#endif
+
+		debug("%s: jumping to address %x\n", __func__, loadaddr);
+		goto start_arm64;
+#endif /* IS_ENABLED(CONFIG_SOC_K3_J721E) */
+	}
+
 	init_env();
 
 	if (!fit_image_info[IMAGE_ID_DM_FW].image_start) {
@@ -250,6 +285,14 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
 		fit_image_info[IMAGE_ID_ATF].image_start =
 			spl_image->entry_point;
 
+#if IS_ENABLED(CONFIG_SOC_K3_J721E)
+	/* Save TF-A image, as at resume fit image is not processed */
+	memcpy((void *)LPM_BL31, (void *)fit_image_info[IMAGE_ID_ATF].image_start,
+	       fit_image_info[IMAGE_ID_ATF].image_len);
+	*(ulong *)(LPM_BL31_START) = fit_image_info[IMAGE_ID_ATF].image_start;
+	*(ulong *)(LPM_BL31_SIZE) = fit_image_info[IMAGE_ID_ATF].image_len;
+#endif
+
 	ret = rproc_load(1, fit_image_info[IMAGE_ID_ATF].image_start, 0x200);
 	if (ret)
 		panic("%s: ATF failed to load on rproc (%d)\n", __func__, ret);
@@ -289,8 +332,18 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
 		loadaddr = load_elf_image_phdr(loadaddr);
 	} else {
 		loadaddr = fit_image_info[IMAGE_ID_DM_FW].image_start;
-		if (valid_elf_image(loadaddr))
+		if (valid_elf_image(loadaddr)) {
 			loadaddr = load_elf_image_phdr(loadaddr);
+#if IS_ENABLED(CONFIG_SOC_K3_J721E)
+			if (fit_image_info[IMAGE_ID_DM_FW].image_len > (BUFFER_ADDR - LPM_DM))
+				log_warning("%s\n: Not enough space to save DM-Firmware",
+					    __func__);
+			else
+				memcpy((void *)LPM_DM,
+				       (void *)fit_image_info[IMAGE_ID_DM_FW].image_start,
+				       fit_image_info[IMAGE_ID_DM_FW].image_len);
+#endif
+		}
 	}
 
 	debug("%s: jumping to address %x\n", __func__, loadaddr);
@@ -299,6 +352,16 @@ start_arm64:
 	/* Add an extra newline to differentiate the ATF logs from SPL */
 	printf("Starting ATF on ARM64 core...\n\n");
 
+#if IS_ENABLED(CONFIG_SOC_K3_J721E)
+	/*
+	 * Write a magic value in scratchpad ram to notify TF-A that the board
+	 * is resuming
+	 */
+	if (board_is_resuming())
+		*(u32 *)(SCRACTHPAD_RAM_BASE) = BL31_MAGIC_SUSPEND;
+	else
+		*(u32 *)(SCRACTHPAD_RAM_BASE) = 0x00;
+#endif
 	ret = rproc_start(1);
 	if (ret)
 		panic("%s: ATF failed to start on rproc (%d)\n", __func__, ret);
diff --git a/arch/arm/mach-k3/include/mach/j721e_hardware.h b/arch/arm/mach-k3/include/mach/j721e_hardware.h
index 376db389ba..29f4030f5e 100644
--- a/arch/arm/mach-k3/include/mach/j721e_hardware.h
+++ b/arch/arm/mach-k3/include/mach/j721e_hardware.h
@@ -15,6 +15,7 @@
 #define WKUP_CTRL_MMR0_BASE				0x43000000
 #define MCU_CTRL_MMR0_BASE				0x40f00000
 #define CTRL_MMR0_BASE					0x00100000
+#define SCRACTHPAD_RAM_BASE				0x40280000
 
 #define CTRLMMR_MAIN_DEVSTAT				(CTRL_MMR0_BASE + 0x30)
 #define MAIN_DEVSTAT_BOOT_MODE_B_MASK		BIT(0)
diff --git a/arch/arm/mach-k3/include/mach/j721e_spl.h b/arch/arm/mach-k3/include/mach/j721e_spl.h
index e8947917a6..253e36b239 100644
--- a/arch/arm/mach-k3/include/mach/j721e_spl.h
+++ b/arch/arm/mach-k3/include/mach/j721e_spl.h
@@ -42,4 +42,34 @@
 #define K3_PRIMARY_BOOTMODE		0x0
 #define K3_BACKUP_BOOTMODE		0x1
 
+/* Starting buffer address is 1MB before the stack address in DDR */
+#define BUFFER_ADDR (CONFIG_SPL_STACK_R_ADDR - SZ_1M)
+
+/* This is actually the whole size of the SRAM */
+#define BL31_SIZE    0x20000
+
+/* This address belongs to a reserved memory region for the point of view of
+ * Linux, U-boot SPL must use the same address to restore TF-A and resume
+ * entry point address
+ */
+#define LPM_SAVE		0xA5000000
+#define LPM_BL31		LPM_SAVE
+#define LPM_BL31_START		LPM_BL31 + BL31_SIZE
+#define LPM_BL31_SIZE		LPM_BL31_START + 4
+#define LPM_DM			LPM_BL31_SIZE  + 4
+
+/* Check if the copy of TF-A and DM-Firmware in DRAM does not overlap an
+ * over memory section.
+ * The resume address of TF-A is also saved in DRAM.
+ * At build time we don't know the DM-Firmware size, so we keep 512k to
+ * save it.
+ */
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_TARGET_J7200_R5_EVM)
+#if ((LPM_DM + SZ_512K) > BUFFER_ADDR)
+#error Not enough space to save DM-Firmware and TF-A for S2R
+#endif
+#endif
+
+#define BL31_MAGIC_SUSPEND 0xA5A5A5A5
+
 #endif
diff --git a/arch/arm/mach-k3/sysfw-loader.c b/arch/arm/mach-k3/sysfw-loader.c
index 9be2d9eaea..e6d452e590 100644
--- a/arch/arm/mach-k3/sysfw-loader.c
+++ b/arch/arm/mach-k3/sysfw-loader.c
@@ -84,13 +84,16 @@ static bool sysfw_loaded;
 static void *sysfw_load_address;
 
 /*
- * Populate SPL hook to override the default load address used by the SPL
- * loader function with a custom address for SYSFW loading.
+ * Populate SPL hook to override the default load address used by the
+ * SPL loader function with a custom address for SYSFW loading. In
+ * other case use also a custom address located in a reserved memory
+ * region. It ensures that Linux memory won't be corrupted by SPL during
+ * suspend to ram.
  */
 struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size)
 {
 	if (sysfw_loaded)
-		return (struct legacy_img_hdr *)(CONFIG_TEXT_BASE + offset);
+		return (struct legacy_img_hdr *)(BUFFER_ADDR + offset);
 	else if (sysfw_load_address)
 		return sysfw_load_address;
 	else
-- 
2.39.2



More information about the U-Boot mailing list