x86: fsp: Save stack address to CMOS for next S3 boot

At the end of pre-relocation phase, save the new stack address
to CMOS and use it as the stack on next S3 boot for fsp_init()
continuation function.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Stefan Roese <sr@denx.de>
diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c
index f2d50ac..3397bb8 100644
--- a/arch/x86/lib/fsp/fsp_common.c
+++ b/arch/x86/lib/fsp/fsp_common.c
@@ -5,8 +5,12 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
+#include <rtc.h>
 #include <asm/acpi_s3.h>
+#include <asm/cmos_layout.h>
+#include <asm/early_cmos.h>
 #include <asm/io.h>
 #include <asm/mrccache.h>
 #include <asm/post.h>
@@ -76,9 +80,36 @@
 	return cache->data;
 }
 
+#ifdef CONFIG_HAVE_ACPI_RESUME
+int fsp_save_s3_stack(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	if (gd->arch.prev_sleep_state == ACPI_S3)
+		return 0;
+
+	ret = uclass_get_device(UCLASS_RTC, 0, &dev);
+	if (ret) {
+		debug("Cannot find RTC: err=%d\n", ret);
+		return -ENODEV;
+	}
+
+	/* Save the stack address to CMOS */
+	ret = rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp);
+	if (ret) {
+		debug("Save stack address to CMOS: err=%d\n", ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+#endif
+
 int arch_fsp_init(void)
 {
 	void *nvs;
+	int stack = CONFIG_FSP_TEMP_RAM_ADDR;
 	int boot_mode = BOOT_FULL_CONFIG;
 #ifdef CONFIG_HAVE_ACPI_RESUME
 	int prev_sleep_state = chipset_prev_sleep_state();
@@ -107,6 +138,11 @@
 				panic("Reboot System");
 			}
 
+			/*
+			 * DM is not avaiable yet at this point, hence call
+			 * CMOS access library which does not depend on DM.
+			 */
+			stack = cmos_read32(CMOS_FSP_STACK_ADDR);
 			boot_mode = BOOT_ON_S3_RESUME;
 		}
 #endif
@@ -115,7 +151,7 @@
 		 * Note the execution does not return to this function,
 		 * instead it jumps to fsp_continue().
 		 */
-		fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, boot_mode, nvs);
+		fsp_init(stack, boot_mode, nvs);
 	} else {
 		/*
 		 * The second time we enter here, adjust the size of malloc()