During the boot a copy of DM-Firmware is done in a reserved memory
area before it starts.
When resuming, R5 SPL uses this copy of DM-Firmware instead of the fit
image.
TF-A which saved itself in this same memory area, is restored in
SRAM by R5 SPL.

Based on the work of Gregory CLEMENT <gregory.clem...@bootlin.com>

Signed-off-by: Thomas Richard <thomas.rich...@bootlin.com>
Signed-off-by: Gregory CLEMENT <gregory.clem...@bootlin.com>

---

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                 | 48 ++++++++++++++++++++++-
 arch/arm/mach-k3/include/mach/j721e_spl.h | 28 +++++++++++++
 arch/arm/mach-k3/sysfw-loader.c           |  9 +++--
 3 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index a35110429b..737a1a28c6 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,32 @@ 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_SAVE))
+                       panic("%s: DM-Firmware image is not valid, it cannot be 
loaded\n",
+                             __func__);
+
+               loadaddr = load_elf_image_phdr(LPM_DM_SAVE);
+
+               /*
+                * Check if the start address of TF-A is in DRAM.
+                * If not it means TF-A was running in SRAM, so it shall be
+                * restored.
+                */
+               if (*(ulong *)(LPM_BL31_START_SAVE) < CFG_SYS_SDRAM_BASE)
+                       memcpy((void *)*(uintptr_t *)(LPM_BL31_START_SAVE),
+                              (void *)LPM_BL31_SAVE, BL31_SIZE);
+
+               ret = rproc_load(1, *(ulong *)(LPM_BL31_RESUME_SAVE), 
BL31_SIZE);
+               if (ret)
+                       panic("%s: ATF failed to load on rproc (%d)\n", 
__func__, ret);
+
+               debug("%s: jumping to address %x\n", __func__, loadaddr);
+               goto start_arm64;
+#endif
+       }
+
        init_env();
 
        if (!fit_image_info[IMAGE_ID_DM_FW].image_start) {
@@ -250,6 +282,10 @@ 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)
+       *(uintptr_t *)(LPM_BL31_START_SAVE) = 
fit_image_info[IMAGE_ID_ATF].image_start;
+#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 +325,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_SAVE))
+                               log_warning("%s\n: Not enough space to save 
DM-Firmware",
+                                           __func__);
+                       else
+                               memcpy((void *)LPM_DM_SAVE,
+                                      (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);
diff --git a/arch/arm/mach-k3/include/mach/j721e_spl.h 
b/arch/arm/mach-k3/include/mach/j721e_spl.h
index e8947917a6..8e0f141ed6 100644
--- a/arch/arm/mach-k3/include/mach/j721e_spl.h
+++ b/arch/arm/mach-k3/include/mach/j721e_spl.h
@@ -42,4 +42,32 @@
 #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_SAVE          LPM_SAVE
+#define LPM_BL31_RESUME_SAVE   LPM_BL31_SAVE + BL31_SIZE
+#define LPM_BL31_START_SAVE    LPM_BL31_RESUME_SAVE + __SIZEOF_POINTER__
+#define LPM_DM_SAVE            LPM_BL31_START_SAVE  + __SIZEOF_POINTER__
+
+/* 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_SAVE + SZ_512K) > BUFFER_ADDR)
+#error Not enough space to save DM-Firmware, TF-A and context for S2R
+#endif
+#endif
+
 #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

Reply via email to