[U-Boot] [PATCH 2/2 v3] mpc85xx/t104x: Add deep sleep framework support

Tang Yuantian Yuantian.Tang at freescale.com
Wed Mar 26 09:08:06 CET 2014


From: Tang Yuantian <yuantian.tang at freescale.com>

When T104x soc wakes up from deep sleep, control is passed to the
primary core that starts executing uboot. After re-initialized some
IP blocks, like DDRC, kernel will take responsibility to continue
to restore environment it leaves before.

Signed-off-by: Tang Yuantian <Yuantian.Tang at freescale.com>
---
v3:
	- fix out-of-tree compile warning
v2: 
	- added explaination for CONFIG_DEEP_SLEEP
	- fixed some issues
 README                                 |  4 +++
 arch/powerpc/cpu/mpc85xx/cpu_init.c    |  7 ++++
 arch/powerpc/cpu/mpc85xx/fdt.c         | 22 ++++++++++++
 arch/powerpc/cpu/mpc85xx/liodn.c       | 27 ++++++++++----
 arch/powerpc/cpu/mpc85xx/start.S       |  9 +++++
 arch/powerpc/include/asm/global_data.h |  2 ++
 arch/powerpc/lib/board.c               | 66 +++++++++++++++++++++++++++++++---
 drivers/ddr/fsl/mpc85xx_ddr_gen3.c     | 42 +++++++++++++++++++---
 include/fdt_support.h                  |  4 +++
 include/fsl_ddr_sdram.h                |  4 +++
 10 files changed, 171 insertions(+), 16 deletions(-)

diff --git a/README b/README
index 216f0c7..25ffb90 100644
--- a/README
+++ b/README
@@ -427,6 +427,10 @@ The following options need to be configured:
 		In this mode, a single differential clock is used to supply
 		clocks to the sysclock, ddrclock and usbclock.
 
+		CONFIG_DEEP_SLEEP
+		Inidcates this SoC supports deep sleep feature. If deep sleep is
+		supported, core will start to execute uboot when wakes up.
+
 - Generic CPU options:
 		CONFIG_SYS_BIG_ENDIAN, CONFIG_SYS_LITTLE_ENDIAN
 
diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c
index 81aeadd..1be29f8 100644
--- a/arch/powerpc/cpu/mpc85xx/cpu_init.c
+++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c
@@ -279,6 +279,7 @@ void cpu_init_f (void)
 #ifdef CONFIG_MPC8548
 	ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR);
 	uint svr = get_svr();
+	gd = (gd_t *)(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET);
 
 	/*
 	 * CPU2 errata workaround: A core hang possible while executing
@@ -330,6 +331,12 @@ void cpu_init_f (void)
 	in_be32(&gur->dcsrcr);
 #endif
 
+#ifdef CONFIG_DEEP_SLEEP
+	/* disable the console if boot from deep sleep */
+	if (in_be32(&gur->scrtsr[0]) & (1 << 3))
+		gd->flags |= GD_FLG_SILENT |
+		    GD_FLG_DEEP_SLEEP | GD_FLG_DISABLE_CONSOLE;
+#endif
 }
 
 /* Implement a dummy function for those platforms w/o SERDES */
diff --git a/arch/powerpc/cpu/mpc85xx/fdt.c b/arch/powerpc/cpu/mpc85xx/fdt.c
index 33bc900..9351f63 100644
--- a/arch/powerpc/cpu/mpc85xx/fdt.c
+++ b/arch/powerpc/cpu/mpc85xx/fdt.c
@@ -35,6 +35,9 @@ void ft_fixup_cpu(void *blob, u64 memory_limit)
 	u32 bootpg = determine_mp_bootpg(NULL);
 	u32 id = get_my_id();
 	const char *enable_method;
+#ifdef CONFIG_DEEP_SLEEP
+	ulong len;
+#endif
 
 	off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4);
 	while (off != -FDT_ERR_NOTFOUND) {
@@ -108,6 +111,25 @@ void ft_fixup_cpu(void *blob, u64 memory_limit)
 			printf("Failed to reserve memory for spin table: %s\n",
 				fdt_strerror(off));
 	}
+
+#ifdef CONFIG_DEEP_SLEEP
+	/*
+	 * reserve the memory space for deep sleep.
+	 * This space will be re-used next time when boot from deep sleep.
+	 * The space includes bd_t, gd_t, stack and uboot image.
+	 * Reserve 1K for stack.
+	 */
+	len = sizeof(bd_t) + sizeof(gd_t) + (1 << 10);
+	/* round up to 4K */
+	len = (len + (4096 - 1)) & ~(4096 - 1);
+
+	off = fdt_add_mem_rsv(blob, gd->relocaddr - len,
+			len + ((ulong)&__bss_end - gd->relocaddr));
+	if (off < 0)
+		printf("Failed to reserve memory for deep sleep: %s\n",
+		       fdt_strerror(off));
+
+#endif
 }
 #endif
 
diff --git a/arch/powerpc/cpu/mpc85xx/liodn.c b/arch/powerpc/cpu/mpc85xx/liodn.c
index 19e130e..a166765 100644
--- a/arch/powerpc/cpu/mpc85xx/liodn.c
+++ b/arch/powerpc/cpu/mpc85xx/liodn.c
@@ -14,6 +14,8 @@
 #include <asm/fsl_portals.h>
 #include <asm/fsl_liodn.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 int get_dpaa_liodn(enum fsl_dpaa_dev dpaa_dev, u32 *liodns, int liodn_offset)
 {
 	liodns[0] = liodn_bases[dpaa_dev].id[0] + liodn_offset;
@@ -164,6 +166,8 @@ static void setup_rman_liodn_base(struct liodn_id_table *tbl, int size)
 
 void set_liodns(void)
 {
+	bool is_deepsleep = false;
+
 	/* setup general liodn offsets */
 	set_liodn(liodn_tbl, liodn_tbl_sz);
 
@@ -179,16 +183,25 @@ void set_liodns(void)
 	}
 
 	/* setup FMAN block(s) liodn bases & offsets if we have one */
+#ifdef CONFIG_DEEP_SLEEP
+	if (gd->flags & GD_FLG_DEEP_SLEEP)
+		is_deepsleep = true;
+#endif
+
 #ifdef CONFIG_SYS_DPAA_FMAN
-	set_liodn(fman1_liodn_tbl, fman1_liodn_tbl_sz);
-	setup_fman_liodn_base(FSL_HW_PORTAL_FMAN1, fman1_liodn_tbl,
-				fman1_liodn_tbl_sz);
+	if (!is_deepsleep) {
+		set_liodn(fman1_liodn_tbl, fman1_liodn_tbl_sz);
+		setup_fman_liodn_base(FSL_HW_PORTAL_FMAN1, fman1_liodn_tbl,
+				      fman1_liodn_tbl_sz);
+	}
+#endif
 
 #if (CONFIG_SYS_NUM_FMAN == 2)
-	set_liodn(fman2_liodn_tbl, fman2_liodn_tbl_sz);
-	setup_fman_liodn_base(FSL_HW_PORTAL_FMAN2, fman2_liodn_tbl,
-				fman2_liodn_tbl_sz);
-#endif
+	if (!is_deepsleep) {
+		set_liodn(fman2_liodn_tbl, fman2_liodn_tbl_sz);
+		setup_fman_liodn_base(FSL_HW_PORTAL_FMAN2, fman2_liodn_tbl,
+				      fman2_liodn_tbl_sz);
+	}
 #endif
 	/* setup PME liodn base */
 	setup_pme_liodn_base();
diff --git a/arch/powerpc/cpu/mpc85xx/start.S b/arch/powerpc/cpu/mpc85xx/start.S
index dbbd8e5..4af7a80 100644
--- a/arch/powerpc/cpu/mpc85xx/start.S
+++ b/arch/powerpc/cpu/mpc85xx/start.S
@@ -1669,6 +1669,15 @@ relocate_code:
 	 * Now relocate code
 	 */
 
+#ifdef CONFIG_DEEP_SLEEP
+	/* don't copy uboot again in warm reset case */
+	mr	r0, r3
+	bl	check_warmboot
+	cmpwi	r3, 0
+	bne	7f
+	mr	r3, r0
+#endif
+
 	cmplw	cr1,r3,r4
 	addi	r0,r5,3
 	srwi.	r0,r0,2
diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h
index 8e59e8b..219e112 100644
--- a/arch/powerpc/include/asm/global_data.h
+++ b/arch/powerpc/include/asm/global_data.h
@@ -117,6 +117,8 @@ struct arch_global_data {
 #include <asm-generic/global_data.h>
 
 #if 1
+/* Indicates the deep sleep case */
+#define GD_FLG_DEEP_SLEEP	0x10000
 #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r2")
 #else /* We could use plain global data, but the resulting code is bigger */
 #define XTRN_DECLARE_GLOBAL_DATA_PTR	extern
diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c
index f86c6f3..bf6ad6a 100644
--- a/arch/powerpc/lib/board.c
+++ b/arch/powerpc/lib/board.c
@@ -319,6 +319,13 @@ static int __fixup_cpu(void)
 
 int fixup_cpu(void) __attribute__((weak, alias("__fixup_cpu")));
 
+#ifdef CONFIG_DEEP_SLEEP
+int check_warmboot(void)
+{
+	return !!(gd->flags & GD_FLG_DEEP_SLEEP);
+}
+#endif
+
 /*
  * This is the first part of the initialization sequence that is
  * implemented in C, but still running from ROM.
@@ -459,10 +466,18 @@ void board_init_f(ulong bootflag)
 
 	/*
 	 * reserve memory for malloc() arena
+	 * don't reserve it in deep sleep case
 	 */
-	addr_sp = addr - TOTAL_MALLOC_LEN;
-	debug("Reserving %dk for malloc() at: %08lx\n",
-	      TOTAL_MALLOC_LEN >> 10, addr_sp);
+#ifdef CONFIG_DEEP_SLEEP
+	if (gd->flags & GD_FLG_DEEP_SLEEP)
+		addr_sp = addr;
+	else
+#endif
+	{
+		addr_sp = addr - TOTAL_MALLOC_LEN;
+		debug("Reserving %dk for malloc() at: %08lx\n",
+		      TOTAL_MALLOC_LEN >> 10, addr_sp);
+	}
 
 	/*
 	 * (permanently) allocate a Board Info struct
@@ -573,6 +588,14 @@ void board_init_r(gd_t *id, ulong dest_addr)
 {
 	bd_t *bd;
 	ulong malloc_start;
+#ifdef CONFIG_DEEP_SLEEP
+	u32 start;
+	int i;
+	struct ccsr_scfg *scfg = (void *)CONFIG_SYS_MPC85xx_SCFG;
+	u64 *src, *dst;
+	typedef void (*func_t)(void);
+	func_t kernel_resume;
+#endif
 
 #ifndef CONFIG_SYS_NO_FLASH
 	ulong flash_size;
@@ -583,6 +606,24 @@ void board_init_r(gd_t *id, ulong dest_addr)
 
 	gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */
 
+#ifdef CONFIG_DEEP_SLEEP
+	/*
+	 * restore 128-byte memory space which corrupted
+	 * by DDRC training.
+	 */
+	if (gd->flags & GD_FLG_DEEP_SLEEP) {
+		src = (u64 *)in_be32(&scfg->sparecr[2]);
+		dst = (u64 *)(0);
+		for (i = 0; i < 128/sizeof(u64); i++) {
+			asm("stw %1, 0(%0); stw %2, 4(%0)" : : "r" (dst),
+			    "r" ((u32)((u64)(uintptr_t)src >> 32)),
+			    "r" ((u32)src) : "memory");
+			dst++;
+			src++;
+		}
+	}
+#endif
+
 	/* The Malloc area is immediately below the monitor copy in DRAM */
 	malloc_start = dest_addr - TOTAL_MALLOC_LEN;
 
@@ -621,7 +662,10 @@ void board_init_r(gd_t *id, ulong dest_addr)
 	/*
 	 * Setup trap handlers
 	 */
-	trap_init(dest_addr);
+#ifdef CONFIG_DEEP_SLEEP
+	if ((gd->flags & GD_FLG_DEEP_SLEEP) == 0)
+#endif
+		trap_init(dest_addr);
 
 #ifdef CONFIG_ADDR_MAP
 	init_addr_map();
@@ -668,7 +712,10 @@ void board_init_r(gd_t *id, ulong dest_addr)
 
 	asm("sync ; isync");
 
-	mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN);
+#ifdef CONFIG_DEEP_SLEEP
+	if ((gd->flags & GD_FLG_DEEP_SLEEP) == 0)
+#endif
+		mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN);
 
 #if !defined(CONFIG_SYS_NO_FLASH)
 	puts("Flash: ");
@@ -725,6 +772,15 @@ void board_init_r(gd_t *id, ulong dest_addr)
 	/* initialize higher level parts of CPU like time base and timers */
 	cpu_init_r();
 
+#ifdef CONFIG_DEEP_SLEEP
+	/* Jump to kernel in deep sleep case */
+	if (gd->flags & GD_FLG_DEEP_SLEEP) {
+		start = in_be32(&scfg->sparecr[1]);
+		kernel_resume = (func_t)start;
+		kernel_resume();
+	}
+#endif
+
 	WATCHDOG_RESET();
 
 #ifdef CONFIG_SPI
diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
index c805086..57ade09 100644
--- a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
+++ b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c
@@ -15,6 +15,7 @@
 #error Invalid setting for CONFIG_CHIP_SELECTS_PER_CTRL
 #endif
 
+DECLARE_GLOBAL_DATA_PTR;
 
 /*
  * regs has the to-be-set values for DDR controller registers
@@ -119,7 +120,13 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	out_be32(&ddr->timing_cfg_0, regs->timing_cfg_0);
 	out_be32(&ddr->timing_cfg_1, regs->timing_cfg_1);
 	out_be32(&ddr->timing_cfg_2, regs->timing_cfg_2);
-	out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
+#ifdef CONFIG_DEEP_SLEEP
+	if (gd->flags & GD_FLG_DEEP_SLEEP)
+		out_be32(&ddr->sdram_cfg_2,
+			 regs->ddr_sdram_cfg_2 & ~SDRAM_CFG2_D_INIT);
+	else
+#endif
+		out_be32(&ddr->sdram_cfg_2, regs->ddr_sdram_cfg_2);
 	out_be32(&ddr->sdram_mode, regs->ddr_sdram_mode);
 	out_be32(&ddr->sdram_mode_2, regs->ddr_sdram_mode_2);
 	out_be32(&ddr->sdram_mode_3, regs->ddr_sdram_mode_3);
@@ -132,8 +139,16 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
 	out_be32(&ddr->sdram_interval, regs->ddr_sdram_interval);
 	out_be32(&ddr->sdram_data_init, regs->ddr_data_init);
 	out_be32(&ddr->sdram_clk_cntl, regs->ddr_sdram_clk_cntl);
-	out_be32(&ddr->init_addr, regs->ddr_init_addr);
-	out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+#ifdef CONFIG_DEEP_SLEEP
+	if (gd->flags & GD_FLG_DEEP_SLEEP) {
+		out_be32(&ddr->init_addr, 0);
+		out_be32(&ddr->init_ext_addr, (1 << 31));
+	} else
+#endif
+	{
+		out_be32(&ddr->init_addr, regs->ddr_init_addr);
+		out_be32(&ddr->init_ext_addr, regs->ddr_init_ext_addr);
+	}
 
 	out_be32(&ddr->timing_cfg_4, regs->timing_cfg_4);
 	out_be32(&ddr->timing_cfg_5, regs->timing_cfg_5);
@@ -374,8 +389,22 @@ step2:
 	udelay(500);
 	asm volatile("sync;isync");
 
+#ifdef CONFIG_DEEP_SLEEP
+	if (gd->flags & GD_FLG_DEEP_SLEEP) {
+		/* enter self-refresh */
+		setbits_be32(&ddr->sdram_cfg_2, (1 << 31));
+		/* do board specific memory setup */
+		board_mem_sleep_setup();
+	}
+#endif
+
 	/* Let the controller go */
-	temp_sdram_cfg = in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI;
+#ifdef CONFIG_DEEP_SLEEP
+	if (gd->flags & GD_FLG_DEEP_SLEEP)
+		temp_sdram_cfg = (in_be32(&ddr->sdram_cfg) | SDRAM_CFG_BI);
+	else
+#endif
+		temp_sdram_cfg = (in_be32(&ddr->sdram_cfg) & ~SDRAM_CFG_BI);
 	out_be32(&ddr->sdram_cfg, temp_sdram_cfg | SDRAM_CFG_MEM_EN);
 	asm volatile("sync;isync");
 
@@ -526,4 +555,9 @@ step2:
 		clrbits_be32(&ddr->sdram_cfg, 0x2);
 	}
 #endif /* CONFIG_SYS_FSL_ERRATUM_DDR111_DDR134 */
+#ifdef CONFIG_DEEP_SLEEP
+	if (gd->flags & GD_FLG_DEEP_SLEEP)
+		/* exit self-refresh */
+		clrbits_be32(&ddr->sdram_cfg_2, (1 << 31));
+#endif
 }
diff --git a/include/fdt_support.h b/include/fdt_support.h
index 9871e2f..43986dc 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -12,6 +12,10 @@
 
 #include <libfdt.h>
 
+#ifdef CONFIG_DEEP_SLEEP
+extern ulong __bss_end;
+#endif
+
 u32 fdt_getprop_u32_default(const void *fdt, const char *path,
 				const char *prop, const u32 dflt);
 int fdt_chosen(void *fdt, int force);
diff --git a/include/fsl_ddr_sdram.h b/include/fsl_ddr_sdram.h
index 2a36431..1629ea9 100644
--- a/include/fsl_ddr_sdram.h
+++ b/include/fsl_ddr_sdram.h
@@ -357,6 +357,10 @@ static int __board_need_mem_reset(void)
 int board_need_mem_reset(void)
 	__attribute__((weak, alias("__board_need_mem_reset")));
 
+void __weak board_mem_sleep_setup(void)
+{
+}
+
 /*
  * The 85xx boards have a common prototype for fixed_sdram so put the
  * declaration here.
-- 
1.8.5




More information about the U-Boot mailing list