xref: /OK3568_Linux_fs/u-boot/board/freescale/common/arm_sleep.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2014 Freescale Semiconductor, Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <asm/io.h>
9*4882a593Smuzhiyun #ifndef CONFIG_ARMV7_NONSEC
10*4882a593Smuzhiyun #error " Deep sleep needs non-secure mode support. "
11*4882a593Smuzhiyun #else
12*4882a593Smuzhiyun #include <asm/secure.h>
13*4882a593Smuzhiyun #endif
14*4882a593Smuzhiyun #include <asm/armv7.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #if defined(CONFIG_ARCH_LS1021A)
17*4882a593Smuzhiyun #include <asm/arch/immap_ls102xa.h>
18*4882a593Smuzhiyun #endif
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "sleep.h"
21*4882a593Smuzhiyun #ifdef CONFIG_U_QE
22*4882a593Smuzhiyun #include <fsl_qe.h>
23*4882a593Smuzhiyun #endif
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
26*4882a593Smuzhiyun 
board_mem_sleep_setup(void)27*4882a593Smuzhiyun void __weak board_mem_sleep_setup(void)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun 
board_sleep_prepare(void)31*4882a593Smuzhiyun void __weak board_sleep_prepare(void)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun 
is_warm_boot(void)35*4882a593Smuzhiyun bool is_warm_boot(void)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	if (in_be32(&gur->crstsr) & DCFG_CCSR_CRSTSR_WDRFR)
40*4882a593Smuzhiyun 		return 1;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	return 0;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
fsl_dp_disable_console(void)45*4882a593Smuzhiyun void fsl_dp_disable_console(void)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun  * When wakeup from deep sleep, the first 128 bytes space
52*4882a593Smuzhiyun  * will be used to do DDR training which corrupts the data
53*4882a593Smuzhiyun  * in there. This function will restore them.
54*4882a593Smuzhiyun  */
dp_ddr_restore(void)55*4882a593Smuzhiyun static void dp_ddr_restore(void)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	u64 *src, *dst;
58*4882a593Smuzhiyun 	int i;
59*4882a593Smuzhiyun 	struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	/* get the address of ddr date from SPARECR3 */
62*4882a593Smuzhiyun 	src = (u64 *)in_le32(&scfg->sparecr[2]);
63*4882a593Smuzhiyun 	dst = (u64 *)CONFIG_SYS_SDRAM_BASE;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	for (i = 0; i < DDR_BUFF_LEN / 8; i++)
66*4882a593Smuzhiyun 		*dst++ = *src++;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun #if defined(CONFIG_ARMV7_PSCI) && defined(CONFIG_ARCH_LS1021A)
ls1_psci_resume_fixup(void)70*4882a593Smuzhiyun void ls1_psci_resume_fixup(void)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	u32 tmp;
73*4882a593Smuzhiyun 	struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #ifdef QIXIS_BASE
76*4882a593Smuzhiyun 	void *qixis_base = (void *)QIXIS_BASE;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* Pull on PCIe RST# */
79*4882a593Smuzhiyun 	out_8(qixis_base + QIXIS_RST_FORCE_3, 0);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	/* disable deep sleep signals in FPGA */
82*4882a593Smuzhiyun 	tmp = in_8(qixis_base + QIXIS_PWR_CTL2);
83*4882a593Smuzhiyun 	tmp &= ~QIXIS_PWR_CTL2_PCTL;
84*4882a593Smuzhiyun 	out_8(qixis_base + QIXIS_PWR_CTL2, tmp);
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	/* Disable wakeup interrupt during deep sleep */
88*4882a593Smuzhiyun 	out_be32(&scfg->pmcintecr, 0);
89*4882a593Smuzhiyun 	/* Clear PMC interrupt status */
90*4882a593Smuzhiyun 	out_be32(&scfg->pmcintsr, 0xffffffff);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	/* Disable Warm Device Reset */
93*4882a593Smuzhiyun 	tmp = in_be32(&scfg->dpslpcr);
94*4882a593Smuzhiyun 	tmp &= ~SCFG_DPSLPCR_WDRR_EN;
95*4882a593Smuzhiyun 	out_be32(&scfg->dpslpcr, tmp);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun #endif
98*4882a593Smuzhiyun 
dp_resume_prepare(void)99*4882a593Smuzhiyun static void dp_resume_prepare(void)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	dp_ddr_restore();
102*4882a593Smuzhiyun 	board_sleep_prepare();
103*4882a593Smuzhiyun 	armv7_init_nonsec();
104*4882a593Smuzhiyun #ifdef CONFIG_U_QE
105*4882a593Smuzhiyun 	u_qe_resume();
106*4882a593Smuzhiyun #endif
107*4882a593Smuzhiyun #if defined(CONFIG_ARMV7_PSCI) && defined(CONFIG_ARCH_LS1021A)
108*4882a593Smuzhiyun 	ls1_psci_resume_fixup();
109*4882a593Smuzhiyun #endif
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
fsl_dp_resume(void)112*4882a593Smuzhiyun int fsl_dp_resume(void)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	u32 start_addr;
115*4882a593Smuzhiyun 	void (*kernel_resume)(void);
116*4882a593Smuzhiyun 	struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (!is_warm_boot())
119*4882a593Smuzhiyun 		return 0;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	dp_resume_prepare();
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	/* Get the entry address and jump to kernel */
124*4882a593Smuzhiyun 	start_addr = in_le32(&scfg->sparecr[3]);
125*4882a593Smuzhiyun 	debug("Entry address is 0x%08x\n", start_addr);
126*4882a593Smuzhiyun 	kernel_resume = (void (*)(void))start_addr;
127*4882a593Smuzhiyun 	secure_ram_addr(_do_nonsec_entry)(kernel_resume, 0, 0, 0);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	return 0;
130*4882a593Smuzhiyun }
131