xref: /arm-trusted-firmware/plat/rockchip/rk3328/drivers/pmu/pmu.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu 
10*91f16700Schasinglulu #include <platform_def.h>
11*91f16700Schasinglulu 
12*91f16700Schasinglulu #include <arch_helpers.h>
13*91f16700Schasinglulu #include <bl31/bl31.h>
14*91f16700Schasinglulu #include <common/debug.h>
15*91f16700Schasinglulu #include <drivers/console.h>
16*91f16700Schasinglulu #include <drivers/delay_timer.h>
17*91f16700Schasinglulu #include <lib/bakery_lock.h>
18*91f16700Schasinglulu #include <lib/mmio.h>
19*91f16700Schasinglulu #include <plat/common/platform.h>
20*91f16700Schasinglulu 
21*91f16700Schasinglulu #include <plat_private.h>
22*91f16700Schasinglulu #include <pmu.h>
23*91f16700Schasinglulu #include <pmu_com.h>
24*91f16700Schasinglulu #include <rk3328_def.h>
25*91f16700Schasinglulu 
26*91f16700Schasinglulu DEFINE_BAKERY_LOCK(rockchip_pd_lock);
27*91f16700Schasinglulu 
28*91f16700Schasinglulu static struct rk3328_sleep_ddr_data ddr_data;
29*91f16700Schasinglulu static __sramdata struct rk3328_sleep_sram_data sram_data;
30*91f16700Schasinglulu 
31*91f16700Schasinglulu static uint32_t cpu_warm_boot_addr;
32*91f16700Schasinglulu 
33*91f16700Schasinglulu #pragma weak rk3328_pmic_suspend
34*91f16700Schasinglulu #pragma weak rk3328_pmic_resume
35*91f16700Schasinglulu 
36*91f16700Schasinglulu static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
37*91f16700Schasinglulu {
38*91f16700Schasinglulu 	uint32_t pd_reg, apm_reg;
39*91f16700Schasinglulu 
40*91f16700Schasinglulu 	pd_reg = mmio_read_32(PMU_BASE + PMU_PWRDN_CON) & BIT(cpu_id);
41*91f16700Schasinglulu 	apm_reg = mmio_read_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id)) &
42*91f16700Schasinglulu 			       BIT(core_pm_en);
43*91f16700Schasinglulu 
44*91f16700Schasinglulu 	if (pd_reg && !apm_reg)
45*91f16700Schasinglulu 		return core_pwr_pd;
46*91f16700Schasinglulu 	else if (!pd_reg && apm_reg)
47*91f16700Schasinglulu 		return core_pwr_wfi;
48*91f16700Schasinglulu 
49*91f16700Schasinglulu 	ERROR("%s: 0x%x, 0x%x\n", __func__, pd_reg, apm_reg);
50*91f16700Schasinglulu 	while (1)
51*91f16700Schasinglulu 	;
52*91f16700Schasinglulu }
53*91f16700Schasinglulu 
54*91f16700Schasinglulu static int cpus_power_domain_on(uint32_t cpu_id)
55*91f16700Schasinglulu {
56*91f16700Schasinglulu 	uint32_t cpu_pd, cfg_info;
57*91f16700Schasinglulu 
58*91f16700Schasinglulu 	cpu_pd = PD_CPU0 + cpu_id;
59*91f16700Schasinglulu 	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
60*91f16700Schasinglulu 
61*91f16700Schasinglulu 	if (cfg_info == core_pwr_pd) {
62*91f16700Schasinglulu 		/* disable apm cfg */
63*91f16700Schasinglulu 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
64*91f16700Schasinglulu 			      CORES_PM_DISABLE);
65*91f16700Schasinglulu 
66*91f16700Schasinglulu 		/* if the cores have be on, power off it firstly */
67*91f16700Schasinglulu 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
68*91f16700Schasinglulu 			mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
69*91f16700Schasinglulu 				      CORES_PM_DISABLE);
70*91f16700Schasinglulu 			pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
71*91f16700Schasinglulu 		}
72*91f16700Schasinglulu 		pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
73*91f16700Schasinglulu 	} else {
74*91f16700Schasinglulu 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
75*91f16700Schasinglulu 			WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id);
76*91f16700Schasinglulu 			return -EINVAL;
77*91f16700Schasinglulu 		}
78*91f16700Schasinglulu 
79*91f16700Schasinglulu 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
80*91f16700Schasinglulu 			      BIT(core_pm_sft_wakeup_en));
81*91f16700Schasinglulu 	}
82*91f16700Schasinglulu 
83*91f16700Schasinglulu 	return 0;
84*91f16700Schasinglulu }
85*91f16700Schasinglulu 
86*91f16700Schasinglulu static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
87*91f16700Schasinglulu {
88*91f16700Schasinglulu 	uint32_t cpu_pd, core_pm_value;
89*91f16700Schasinglulu 
90*91f16700Schasinglulu 	cpu_pd = PD_CPU0 + cpu_id;
91*91f16700Schasinglulu 	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
92*91f16700Schasinglulu 		return 0;
93*91f16700Schasinglulu 
94*91f16700Schasinglulu 	if (pd_cfg == core_pwr_pd) {
95*91f16700Schasinglulu 		if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK))
96*91f16700Schasinglulu 			return -EINVAL;
97*91f16700Schasinglulu 		/* disable apm cfg */
98*91f16700Schasinglulu 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
99*91f16700Schasinglulu 			      CORES_PM_DISABLE);
100*91f16700Schasinglulu 		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
101*91f16700Schasinglulu 	} else {
102*91f16700Schasinglulu 		core_pm_value = BIT(core_pm_en) | BIT(core_pm_dis_int);
103*91f16700Schasinglulu 		if (pd_cfg == core_pwr_wfi_int)
104*91f16700Schasinglulu 			core_pm_value |= BIT(core_pm_int_wakeup_en);
105*91f16700Schasinglulu 
106*91f16700Schasinglulu 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
107*91f16700Schasinglulu 			      core_pm_value);
108*91f16700Schasinglulu 	}
109*91f16700Schasinglulu 
110*91f16700Schasinglulu 	return 0;
111*91f16700Schasinglulu }
112*91f16700Schasinglulu 
113*91f16700Schasinglulu static void nonboot_cpus_off(void)
114*91f16700Schasinglulu {
115*91f16700Schasinglulu 	uint32_t boot_cpu, cpu;
116*91f16700Schasinglulu 
117*91f16700Schasinglulu 	/* turn off noboot cpus */
118*91f16700Schasinglulu 	boot_cpu = plat_my_core_pos();
119*91f16700Schasinglulu 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
120*91f16700Schasinglulu 		if (cpu == boot_cpu)
121*91f16700Schasinglulu 			continue;
122*91f16700Schasinglulu 		cpus_power_domain_off(cpu, core_pwr_pd);
123*91f16700Schasinglulu 	}
124*91f16700Schasinglulu }
125*91f16700Schasinglulu 
126*91f16700Schasinglulu void sram_save(void)
127*91f16700Schasinglulu {
128*91f16700Schasinglulu 	/* TODO: support the sdram save for rk3328 SoCs*/
129*91f16700Schasinglulu }
130*91f16700Schasinglulu 
131*91f16700Schasinglulu void sram_restore(void)
132*91f16700Schasinglulu {
133*91f16700Schasinglulu 	/* TODO: support the sdram restore for rk3328 SoCs */
134*91f16700Schasinglulu }
135*91f16700Schasinglulu 
136*91f16700Schasinglulu int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
137*91f16700Schasinglulu {
138*91f16700Schasinglulu 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
139*91f16700Schasinglulu 
140*91f16700Schasinglulu 	assert(cpu_id < PLATFORM_CORE_COUNT);
141*91f16700Schasinglulu 	assert(cpuson_flags[cpu_id] == 0);
142*91f16700Schasinglulu 	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
143*91f16700Schasinglulu 	cpuson_entry_point[cpu_id] = entrypoint;
144*91f16700Schasinglulu 	dsb();
145*91f16700Schasinglulu 
146*91f16700Schasinglulu 	cpus_power_domain_on(cpu_id);
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 	return 0;
149*91f16700Schasinglulu }
150*91f16700Schasinglulu 
151*91f16700Schasinglulu int rockchip_soc_cores_pwr_dm_off(void)
152*91f16700Schasinglulu {
153*91f16700Schasinglulu 	uint32_t cpu_id = plat_my_core_pos();
154*91f16700Schasinglulu 
155*91f16700Schasinglulu 	cpus_power_domain_off(cpu_id, core_pwr_wfi);
156*91f16700Schasinglulu 
157*91f16700Schasinglulu 	return 0;
158*91f16700Schasinglulu }
159*91f16700Schasinglulu 
160*91f16700Schasinglulu int rockchip_soc_cores_pwr_dm_suspend(void)
161*91f16700Schasinglulu {
162*91f16700Schasinglulu 	uint32_t cpu_id = plat_my_core_pos();
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	assert(cpu_id < PLATFORM_CORE_COUNT);
165*91f16700Schasinglulu 	assert(cpuson_flags[cpu_id] == 0);
166*91f16700Schasinglulu 	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
167*91f16700Schasinglulu 	cpuson_entry_point[cpu_id] = (uintptr_t)plat_get_sec_entrypoint();
168*91f16700Schasinglulu 	dsb();
169*91f16700Schasinglulu 
170*91f16700Schasinglulu 	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
171*91f16700Schasinglulu 
172*91f16700Schasinglulu 	return 0;
173*91f16700Schasinglulu }
174*91f16700Schasinglulu 
175*91f16700Schasinglulu int rockchip_soc_cores_pwr_dm_on_finish(void)
176*91f16700Schasinglulu {
177*91f16700Schasinglulu 	uint32_t cpu_id = plat_my_core_pos();
178*91f16700Schasinglulu 
179*91f16700Schasinglulu 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE);
180*91f16700Schasinglulu 
181*91f16700Schasinglulu 	return 0;
182*91f16700Schasinglulu }
183*91f16700Schasinglulu 
184*91f16700Schasinglulu int rockchip_soc_cores_pwr_dm_resume(void)
185*91f16700Schasinglulu {
186*91f16700Schasinglulu 	uint32_t cpu_id = plat_my_core_pos();
187*91f16700Schasinglulu 
188*91f16700Schasinglulu 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE);
189*91f16700Schasinglulu 
190*91f16700Schasinglulu 	return 0;
191*91f16700Schasinglulu }
192*91f16700Schasinglulu 
193*91f16700Schasinglulu void __dead2 rockchip_soc_soft_reset(void)
194*91f16700Schasinglulu {
195*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(CPLL_ID));
196*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(GPLL_ID));
197*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(NPLL_ID));
198*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(APLL_ID));
199*91f16700Schasinglulu 	dsb();
200*91f16700Schasinglulu 
201*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE);
202*91f16700Schasinglulu 	dsb();
203*91f16700Schasinglulu 	/*
204*91f16700Schasinglulu 	 * Maybe the HW needs some times to reset the system,
205*91f16700Schasinglulu 	 * so we do not hope the core to execute valid codes.
206*91f16700Schasinglulu 	 */
207*91f16700Schasinglulu 	while (1)
208*91f16700Schasinglulu 		;
209*91f16700Schasinglulu }
210*91f16700Schasinglulu 
211*91f16700Schasinglulu /*
212*91f16700Schasinglulu  * For PMIC RK805, its sleep pin is connect with gpio2_d2 from rk3328.
213*91f16700Schasinglulu  * If the PMIC is configured for responding the sleep pin to power off it,
214*91f16700Schasinglulu  * once the pin is output high,  it will get the pmic power off.
215*91f16700Schasinglulu  */
216*91f16700Schasinglulu void __dead2 rockchip_soc_system_off(void)
217*91f16700Schasinglulu {
218*91f16700Schasinglulu 	uint32_t val;
219*91f16700Schasinglulu 
220*91f16700Schasinglulu 	/* gpio config */
221*91f16700Schasinglulu 	val = mmio_read_32(GRF_BASE + GRF_GPIO2D_IOMUX);
222*91f16700Schasinglulu 	val &= ~GPIO2_D2_GPIO_MODE;
223*91f16700Schasinglulu 	mmio_write_32(GRF_BASE + GRF_GPIO2D_IOMUX, val);
224*91f16700Schasinglulu 
225*91f16700Schasinglulu 	/* config output */
226*91f16700Schasinglulu 	val = mmio_read_32(GPIO2_BASE + SWPORTA_DDR);
227*91f16700Schasinglulu 	val |= GPIO2_D2;
228*91f16700Schasinglulu 	mmio_write_32(GPIO2_BASE + SWPORTA_DDR, val);
229*91f16700Schasinglulu 
230*91f16700Schasinglulu 	/* config output high level */
231*91f16700Schasinglulu 	val = mmio_read_32(GPIO2_BASE);
232*91f16700Schasinglulu 	val |= GPIO2_D2;
233*91f16700Schasinglulu 	mmio_write_32(GPIO2_BASE, val);
234*91f16700Schasinglulu 	dsb();
235*91f16700Schasinglulu 
236*91f16700Schasinglulu 	while (1)
237*91f16700Schasinglulu 		;
238*91f16700Schasinglulu }
239*91f16700Schasinglulu 
240*91f16700Schasinglulu static uint32_t clk_ungt_msk[CRU_CLKGATE_NUMS] = {
241*91f16700Schasinglulu 	0x187f, 0x0000, 0x010c, 0x0000, 0x0200,
242*91f16700Schasinglulu 	0x0010, 0x0000, 0x0017, 0x001f, 0x0000,
243*91f16700Schasinglulu 	0x0000, 0x0000, 0x0000, 0x0003, 0x0000,
244*91f16700Schasinglulu 	0xf001, 0x27c0, 0x04D9, 0x03ff, 0x0000,
245*91f16700Schasinglulu 	0x0000, 0x0000, 0x0010, 0x0000, 0x0000,
246*91f16700Schasinglulu 	0x0000, 0x0000, 0x0003, 0x0008
247*91f16700Schasinglulu };
248*91f16700Schasinglulu 
249*91f16700Schasinglulu static void clks_gating_suspend(uint32_t *ungt_msk)
250*91f16700Schasinglulu {
251*91f16700Schasinglulu 	int i;
252*91f16700Schasinglulu 
253*91f16700Schasinglulu 	for (i = 0; i < CRU_CLKGATE_NUMS; i++) {
254*91f16700Schasinglulu 		ddr_data.clk_ungt_save[i] =
255*91f16700Schasinglulu 			mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i));
256*91f16700Schasinglulu 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
257*91f16700Schasinglulu 			      ((~ungt_msk[i]) << 16) | 0xffff);
258*91f16700Schasinglulu 	}
259*91f16700Schasinglulu }
260*91f16700Schasinglulu 
261*91f16700Schasinglulu static void clks_gating_resume(void)
262*91f16700Schasinglulu {
263*91f16700Schasinglulu 	int i;
264*91f16700Schasinglulu 
265*91f16700Schasinglulu 	for (i = 0; i < CRU_CLKGATE_NUMS; i++)
266*91f16700Schasinglulu 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
267*91f16700Schasinglulu 			      ddr_data.clk_ungt_save[i] | 0xffff0000);
268*91f16700Schasinglulu }
269*91f16700Schasinglulu 
270*91f16700Schasinglulu static inline void pm_pll_wait_lock(uint32_t pll_id)
271*91f16700Schasinglulu {
272*91f16700Schasinglulu 	uint32_t delay = PLL_LOCKED_TIMEOUT;
273*91f16700Schasinglulu 
274*91f16700Schasinglulu 	while (delay > 0) {
275*91f16700Schasinglulu 		if (mmio_read_32(CRU_BASE + PLL_CONS(pll_id, 1)) &
276*91f16700Schasinglulu 		    PLL_IS_LOCKED)
277*91f16700Schasinglulu 			break;
278*91f16700Schasinglulu 		delay--;
279*91f16700Schasinglulu 	}
280*91f16700Schasinglulu 	if (delay == 0)
281*91f16700Schasinglulu 		ERROR("lock-pll: %d\n", pll_id);
282*91f16700Schasinglulu }
283*91f16700Schasinglulu 
284*91f16700Schasinglulu static inline void pll_pwr_dwn(uint32_t pll_id, uint32_t pd)
285*91f16700Schasinglulu {
286*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
287*91f16700Schasinglulu 		      BITS_WITH_WMASK(1U, 1U, 15));
288*91f16700Schasinglulu 	if (pd)
289*91f16700Schasinglulu 		mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
290*91f16700Schasinglulu 			      BITS_WITH_WMASK(1, 1, 14));
291*91f16700Schasinglulu 	else
292*91f16700Schasinglulu 		mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
293*91f16700Schasinglulu 			      BITS_WITH_WMASK(0, 1, 14));
294*91f16700Schasinglulu }
295*91f16700Schasinglulu 
296*91f16700Schasinglulu static __sramfunc void dpll_suspend(void)
297*91f16700Schasinglulu {
298*91f16700Schasinglulu 	int i;
299*91f16700Schasinglulu 
300*91f16700Schasinglulu 	/* slow mode */
301*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(DPLL_ID));
302*91f16700Schasinglulu 
303*91f16700Schasinglulu 	/* save pll con */
304*91f16700Schasinglulu 	for (i = 0; i < CRU_PLL_CON_NUMS; i++)
305*91f16700Schasinglulu 		sram_data.dpll_con_save[i] =
306*91f16700Schasinglulu 				mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, i));
307*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
308*91f16700Schasinglulu 		      BITS_WITH_WMASK(1U, 1U, 15));
309*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
310*91f16700Schasinglulu 		      BITS_WITH_WMASK(1, 1, 14));
311*91f16700Schasinglulu }
312*91f16700Schasinglulu 
313*91f16700Schasinglulu static __sramfunc void dpll_resume(void)
314*91f16700Schasinglulu {
315*91f16700Schasinglulu 	uint32_t delay = PLL_LOCKED_TIMEOUT;
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
318*91f16700Schasinglulu 		      BITS_WITH_WMASK(1U, 1U, 15));
319*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
320*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 1, 14));
321*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1),
322*91f16700Schasinglulu 		      sram_data.dpll_con_save[1] | 0xc0000000);
323*91f16700Schasinglulu 
324*91f16700Schasinglulu 	dsb();
325*91f16700Schasinglulu 
326*91f16700Schasinglulu 	while (delay > 0) {
327*91f16700Schasinglulu 		if (mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, 1)) &
328*91f16700Schasinglulu 				 PLL_IS_LOCKED)
329*91f16700Schasinglulu 			break;
330*91f16700Schasinglulu 		delay--;
331*91f16700Schasinglulu 	}
332*91f16700Schasinglulu 	if (delay == 0)
333*91f16700Schasinglulu 		while (1)
334*91f16700Schasinglulu 			;
335*91f16700Schasinglulu 
336*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CRU_MODE,
337*91f16700Schasinglulu 		      PLL_NORM_MODE(DPLL_ID));
338*91f16700Schasinglulu }
339*91f16700Schasinglulu 
340*91f16700Schasinglulu static inline void pll_suspend(uint32_t pll_id)
341*91f16700Schasinglulu {
342*91f16700Schasinglulu 	int i;
343*91f16700Schasinglulu 
344*91f16700Schasinglulu 	/* slow mode */
345*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(pll_id));
346*91f16700Schasinglulu 
347*91f16700Schasinglulu 	/* save pll con */
348*91f16700Schasinglulu 	for (i = 0; i < CRU_PLL_CON_NUMS; i++)
349*91f16700Schasinglulu 		ddr_data.cru_plls_con_save[pll_id][i] =
350*91f16700Schasinglulu 				mmio_read_32(CRU_BASE + PLL_CONS(pll_id, i));
351*91f16700Schasinglulu 
352*91f16700Schasinglulu 	/* powerdown pll */
353*91f16700Schasinglulu 	pll_pwr_dwn(pll_id, pmu_pd_off);
354*91f16700Schasinglulu }
355*91f16700Schasinglulu 
356*91f16700Schasinglulu static inline void pll_resume(uint32_t pll_id)
357*91f16700Schasinglulu {
358*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1),
359*91f16700Schasinglulu 		      ddr_data.cru_plls_con_save[pll_id][1] | 0xc0000000);
360*91f16700Schasinglulu 
361*91f16700Schasinglulu 	pm_pll_wait_lock(pll_id);
362*91f16700Schasinglulu 
363*91f16700Schasinglulu 	if (PLL_IS_NORM_MODE(ddr_data.cru_mode_save, pll_id))
364*91f16700Schasinglulu 		mmio_write_32(CRU_BASE + CRU_CRU_MODE,
365*91f16700Schasinglulu 			      PLL_NORM_MODE(pll_id));
366*91f16700Schasinglulu }
367*91f16700Schasinglulu 
368*91f16700Schasinglulu static void pm_plls_suspend(void)
369*91f16700Schasinglulu {
370*91f16700Schasinglulu 	ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_CRU_MODE);
371*91f16700Schasinglulu 	ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(0));
372*91f16700Schasinglulu 	ddr_data.clk_sel1 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(1));
373*91f16700Schasinglulu 	ddr_data.clk_sel18 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(18));
374*91f16700Schasinglulu 	ddr_data.clk_sel20 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(20));
375*91f16700Schasinglulu 	ddr_data.clk_sel24 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(24));
376*91f16700Schasinglulu 	ddr_data.clk_sel38 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(38));
377*91f16700Schasinglulu 	pll_suspend(NPLL_ID);
378*91f16700Schasinglulu 	pll_suspend(CPLL_ID);
379*91f16700Schasinglulu 	pll_suspend(GPLL_ID);
380*91f16700Schasinglulu 	pll_suspend(APLL_ID);
381*91f16700Schasinglulu 
382*91f16700Schasinglulu 	/* core */
383*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(0),
384*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0x1f, 0));
385*91f16700Schasinglulu 
386*91f16700Schasinglulu 	/* pclk_dbg */
387*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(1),
388*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0xf, 0));
389*91f16700Schasinglulu 
390*91f16700Schasinglulu 	/* crypto */
391*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(20),
392*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0x1f, 0));
393*91f16700Schasinglulu 
394*91f16700Schasinglulu 	/* pwm0 */
395*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(24),
396*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0x7f, 8));
397*91f16700Schasinglulu 
398*91f16700Schasinglulu 	/* uart2 from 24M */
399*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(18),
400*91f16700Schasinglulu 		      BITS_WITH_WMASK(2, 0x3, 8));
401*91f16700Schasinglulu 
402*91f16700Schasinglulu 	/* clk_rtc32k */
403*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(38),
404*91f16700Schasinglulu 		      BITS_WITH_WMASK(767, 0x3fff, 0) |
405*91f16700Schasinglulu 		      BITS_WITH_WMASK(2U, 0x3u, 14));
406*91f16700Schasinglulu }
407*91f16700Schasinglulu 
408*91f16700Schasinglulu static void pm_plls_resume(void)
409*91f16700Schasinglulu {
410*91f16700Schasinglulu 	/* clk_rtc32k */
411*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(38),
412*91f16700Schasinglulu 		      ddr_data.clk_sel38 |
413*91f16700Schasinglulu 		      BITS_WMSK(0x3fff, 0) |
414*91f16700Schasinglulu 		      BITS_WMSK(0x3u, 14));
415*91f16700Schasinglulu 
416*91f16700Schasinglulu 	/* uart2 */
417*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(18),
418*91f16700Schasinglulu 		      ddr_data.clk_sel18 | BITS_WMSK(0x3, 8));
419*91f16700Schasinglulu 
420*91f16700Schasinglulu 	/* pwm0 */
421*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(24),
422*91f16700Schasinglulu 		      ddr_data.clk_sel24 | BITS_WMSK(0x7f, 8));
423*91f16700Schasinglulu 
424*91f16700Schasinglulu 	/* crypto */
425*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(20),
426*91f16700Schasinglulu 		      ddr_data.clk_sel20 | BITS_WMSK(0x1f, 0));
427*91f16700Schasinglulu 
428*91f16700Schasinglulu 	/* pclk_dbg */
429*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(1),
430*91f16700Schasinglulu 		      ddr_data.clk_sel1 | BITS_WMSK(0xf, 0));
431*91f16700Schasinglulu 
432*91f16700Schasinglulu 	/* core */
433*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(0),
434*91f16700Schasinglulu 		      ddr_data.clk_sel0 | BITS_WMSK(0x1f, 0));
435*91f16700Schasinglulu 
436*91f16700Schasinglulu 	pll_pwr_dwn(APLL_ID, pmu_pd_on);
437*91f16700Schasinglulu 	pll_pwr_dwn(GPLL_ID, pmu_pd_on);
438*91f16700Schasinglulu 	pll_pwr_dwn(CPLL_ID, pmu_pd_on);
439*91f16700Schasinglulu 	pll_pwr_dwn(NPLL_ID, pmu_pd_on);
440*91f16700Schasinglulu 
441*91f16700Schasinglulu 	pll_resume(APLL_ID);
442*91f16700Schasinglulu 	pll_resume(GPLL_ID);
443*91f16700Schasinglulu 	pll_resume(CPLL_ID);
444*91f16700Schasinglulu 	pll_resume(NPLL_ID);
445*91f16700Schasinglulu }
446*91f16700Schasinglulu 
447*91f16700Schasinglulu #define ARCH_TIMER_TICKS_PER_US (SYS_COUNTER_FREQ_IN_TICKS / 1000000)
448*91f16700Schasinglulu 
449*91f16700Schasinglulu static __sramfunc void sram_udelay(uint32_t us)
450*91f16700Schasinglulu {
451*91f16700Schasinglulu 	uint64_t pct_orig, pct_now;
452*91f16700Schasinglulu 	uint64_t to_wait = ARCH_TIMER_TICKS_PER_US * us;
453*91f16700Schasinglulu 
454*91f16700Schasinglulu 	isb();
455*91f16700Schasinglulu 	pct_orig = read_cntpct_el0();
456*91f16700Schasinglulu 
457*91f16700Schasinglulu 	do {
458*91f16700Schasinglulu 		isb();
459*91f16700Schasinglulu 		pct_now = read_cntpct_el0();
460*91f16700Schasinglulu 	} while ((pct_now - pct_orig) <= to_wait);
461*91f16700Schasinglulu }
462*91f16700Schasinglulu 
463*91f16700Schasinglulu /*
464*91f16700Schasinglulu  * For PMIC RK805, its sleep pin is connect with gpio2_d2 from rk3328.
465*91f16700Schasinglulu  * If the PMIC is configured for responding the sleep pin
466*91f16700Schasinglulu  * to get it into sleep mode,
467*91f16700Schasinglulu  * once the pin is output high,  it will get the pmic into sleep mode.
468*91f16700Schasinglulu  */
469*91f16700Schasinglulu __sramfunc void rk3328_pmic_suspend(void)
470*91f16700Schasinglulu {
471*91f16700Schasinglulu 	sram_data.pmic_sleep_save = mmio_read_32(GRF_BASE + PMIC_SLEEP_REG);
472*91f16700Schasinglulu 	sram_data.pmic_sleep_gpio_save[1] = mmio_read_32(GPIO2_BASE + 4);
473*91f16700Schasinglulu 	sram_data.pmic_sleep_gpio_save[0] = mmio_read_32(GPIO2_BASE);
474*91f16700Schasinglulu 	mmio_write_32(GRF_BASE + PMIC_SLEEP_REG, BITS_WITH_WMASK(0, 0x3, 4));
475*91f16700Schasinglulu 	mmio_write_32(GPIO2_BASE + 4,
476*91f16700Schasinglulu 		      sram_data.pmic_sleep_gpio_save[1] | BIT(26));
477*91f16700Schasinglulu 	mmio_write_32(GPIO2_BASE,
478*91f16700Schasinglulu 		      sram_data.pmic_sleep_gpio_save[0] | BIT(26));
479*91f16700Schasinglulu }
480*91f16700Schasinglulu 
481*91f16700Schasinglulu __sramfunc void  rk3328_pmic_resume(void)
482*91f16700Schasinglulu {
483*91f16700Schasinglulu 	mmio_write_32(GPIO2_BASE, sram_data.pmic_sleep_gpio_save[0]);
484*91f16700Schasinglulu 	mmio_write_32(GPIO2_BASE + 4, sram_data.pmic_sleep_gpio_save[1]);
485*91f16700Schasinglulu 	mmio_write_32(GRF_BASE + PMIC_SLEEP_REG,
486*91f16700Schasinglulu 		      sram_data.pmic_sleep_save | BITS_WMSK(0xffffu, 0));
487*91f16700Schasinglulu 	/* Resuming volt need a lot of time */
488*91f16700Schasinglulu 	sram_udelay(100);
489*91f16700Schasinglulu }
490*91f16700Schasinglulu 
491*91f16700Schasinglulu static __sramfunc void ddr_suspend(void)
492*91f16700Schasinglulu {
493*91f16700Schasinglulu 	sram_data.pd_sr_idle_save = mmio_read_32(DDR_UPCTL_BASE +
494*91f16700Schasinglulu 						 DDR_PCTL2_PWRCTL);
495*91f16700Schasinglulu 	sram_data.pd_sr_idle_save &= SELFREF_EN;
496*91f16700Schasinglulu 
497*91f16700Schasinglulu 	mmio_clrbits_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL, SELFREF_EN);
498*91f16700Schasinglulu 	sram_data.ddr_grf_con0 = mmio_read_32(DDR_GRF_BASE +
499*91f16700Schasinglulu 					      DDRGRF_SOC_CON(0));
500*91f16700Schasinglulu 	mmio_write_32(DDR_GRF_BASE, BIT_WITH_WMSK(14) | WMSK_BIT(15));
501*91f16700Schasinglulu 
502*91f16700Schasinglulu 	/*
503*91f16700Schasinglulu 	 * Override csysreq from ddrc and
504*91f16700Schasinglulu 	 * send valid csysreq signal to PMU,
505*91f16700Schasinglulu 	 * csysreq is controlled by ddrc only
506*91f16700Schasinglulu 	 */
507*91f16700Schasinglulu 
508*91f16700Schasinglulu 	/* in self-refresh */
509*91f16700Schasinglulu 	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(0));
510*91f16700Schasinglulu 	while ((mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_STATUS(1)) &
511*91f16700Schasinglulu 	       (0x03 << 12)) !=  (0x02 << 12))
512*91f16700Schasinglulu 		;
513*91f16700Schasinglulu 	/* ddr retention */
514*91f16700Schasinglulu 	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(2));
515*91f16700Schasinglulu 
516*91f16700Schasinglulu 	/* ddr gating */
517*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(0),
518*91f16700Schasinglulu 		      BITS_WITH_WMASK(0x7, 0x7, 4));
519*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(7),
520*91f16700Schasinglulu 		      BITS_WITH_WMASK(1, 1, 4));
521*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
522*91f16700Schasinglulu 		      BITS_WITH_WMASK(0x1ff, 0x1ff, 1));
523*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(27),
524*91f16700Schasinglulu 		      BITS_WITH_WMASK(0x3, 0x3, 0));
525*91f16700Schasinglulu 
526*91f16700Schasinglulu 	dpll_suspend();
527*91f16700Schasinglulu }
528*91f16700Schasinglulu 
529*91f16700Schasinglulu __sramfunc  void dmc_restore(void)
530*91f16700Schasinglulu {
531*91f16700Schasinglulu 	dpll_resume();
532*91f16700Schasinglulu 
533*91f16700Schasinglulu 	/* ddr gating */
534*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(0),
535*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0x7, 4));
536*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(7),
537*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 1, 4));
538*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
539*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0x1ff, 1));
540*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(27),
541*91f16700Schasinglulu 		      BITS_WITH_WMASK(0, 0x3, 0));
542*91f16700Schasinglulu 
543*91f16700Schasinglulu 	/* ddr de_retention */
544*91f16700Schasinglulu 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(2));
545*91f16700Schasinglulu 	/* exit self-refresh */
546*91f16700Schasinglulu 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(0));
547*91f16700Schasinglulu 	while ((mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_STATUS(1)) &
548*91f16700Schasinglulu 		(0x03 << 12)) !=  (0x00 << 12))
549*91f16700Schasinglulu 		;
550*91f16700Schasinglulu 
551*91f16700Schasinglulu 	mmio_write_32(DDR_GRF_BASE, sram_data.ddr_grf_con0 | 0xc0000000);
552*91f16700Schasinglulu 	if (sram_data.pd_sr_idle_save)
553*91f16700Schasinglulu 		mmio_setbits_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL,
554*91f16700Schasinglulu 				SELFREF_EN);
555*91f16700Schasinglulu }
556*91f16700Schasinglulu 
557*91f16700Schasinglulu static __sramfunc void sram_dbg_uart_suspend(void)
558*91f16700Schasinglulu {
559*91f16700Schasinglulu 	sram_data.uart2_ier = mmio_read_32(UART2_BASE + UART_IER);
560*91f16700Schasinglulu 	mmio_write_32(UART2_BASE + UART_IER, UART_INT_DISABLE);
561*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20002000);
562*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040004);
563*91f16700Schasinglulu }
564*91f16700Schasinglulu 
565*91f16700Schasinglulu __sramfunc void sram_dbg_uart_resume(void)
566*91f16700Schasinglulu {
567*91f16700Schasinglulu 	/* restore uart clk and reset fifo */
568*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20000000);
569*91f16700Schasinglulu 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040000);
570*91f16700Schasinglulu 	mmio_write_32(UART2_BASE + UART_FCR, UART_FIFO_RESET);
571*91f16700Schasinglulu 	mmio_write_32(UART2_BASE + UART_IER, sram_data.uart2_ier);
572*91f16700Schasinglulu }
573*91f16700Schasinglulu 
574*91f16700Schasinglulu static __sramfunc void sram_soc_enter_lp(void)
575*91f16700Schasinglulu {
576*91f16700Schasinglulu 	uint32_t apm_value;
577*91f16700Schasinglulu 
578*91f16700Schasinglulu 	apm_value = BIT(core_pm_en) |
579*91f16700Schasinglulu 		    BIT(core_pm_dis_int) |
580*91f16700Schasinglulu 		    BIT(core_pm_int_wakeup_en);
581*91f16700Schasinglulu 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(PD_CPU0), apm_value);
582*91f16700Schasinglulu 
583*91f16700Schasinglulu 	dsb();
584*91f16700Schasinglulu 	isb();
585*91f16700Schasinglulu err_loop:
586*91f16700Schasinglulu 	wfi();
587*91f16700Schasinglulu 	/*
588*91f16700Schasinglulu 	 *Soc will enter low power mode and
589*91f16700Schasinglulu 	 *do not return to here.
590*91f16700Schasinglulu 	 */
591*91f16700Schasinglulu 	goto err_loop;
592*91f16700Schasinglulu }
593*91f16700Schasinglulu 
594*91f16700Schasinglulu __sramfunc void sram_suspend(void)
595*91f16700Schasinglulu {
596*91f16700Schasinglulu 	/* disable mmu and icache */
597*91f16700Schasinglulu 	disable_mmu_icache_el3();
598*91f16700Schasinglulu 	tlbialle3();
599*91f16700Schasinglulu 	dsbsy();
600*91f16700Schasinglulu 	isb();
601*91f16700Schasinglulu 
602*91f16700Schasinglulu 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
603*91f16700Schasinglulu 		      ((uintptr_t)&pmu_cpuson_entrypoint >> CPU_BOOT_ADDR_ALIGN) |
604*91f16700Schasinglulu 		      CPU_BOOT_ADDR_WMASK);
605*91f16700Schasinglulu 
606*91f16700Schasinglulu 	/* ddr self-refresh and gating phy */
607*91f16700Schasinglulu 	ddr_suspend();
608*91f16700Schasinglulu 
609*91f16700Schasinglulu 	rk3328_pmic_suspend();
610*91f16700Schasinglulu 
611*91f16700Schasinglulu 	sram_dbg_uart_suspend();
612*91f16700Schasinglulu 
613*91f16700Schasinglulu 	sram_soc_enter_lp();
614*91f16700Schasinglulu }
615*91f16700Schasinglulu 
616*91f16700Schasinglulu void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
617*91f16700Schasinglulu {
618*91f16700Schasinglulu 	sram_suspend();
619*91f16700Schasinglulu 
620*91f16700Schasinglulu 	/* should never reach here */
621*91f16700Schasinglulu 	psci_power_down_wfi();
622*91f16700Schasinglulu }
623*91f16700Schasinglulu 
624*91f16700Schasinglulu int rockchip_soc_sys_pwr_dm_suspend(void)
625*91f16700Schasinglulu {
626*91f16700Schasinglulu 	clks_gating_suspend(clk_ungt_msk);
627*91f16700Schasinglulu 
628*91f16700Schasinglulu 	pm_plls_suspend();
629*91f16700Schasinglulu 
630*91f16700Schasinglulu 	return 0;
631*91f16700Schasinglulu }
632*91f16700Schasinglulu 
633*91f16700Schasinglulu int rockchip_soc_sys_pwr_dm_resume(void)
634*91f16700Schasinglulu {
635*91f16700Schasinglulu 	pm_plls_resume();
636*91f16700Schasinglulu 
637*91f16700Schasinglulu 	clks_gating_resume();
638*91f16700Schasinglulu 
639*91f16700Schasinglulu 	plat_rockchip_gic_cpuif_enable();
640*91f16700Schasinglulu 
641*91f16700Schasinglulu 	return 0;
642*91f16700Schasinglulu }
643*91f16700Schasinglulu 
644*91f16700Schasinglulu void rockchip_plat_mmu_el3(void)
645*91f16700Schasinglulu {
646*91f16700Schasinglulu 	/* TODO: support the el3 for rk3328 SoCs */
647*91f16700Schasinglulu }
648*91f16700Schasinglulu 
649*91f16700Schasinglulu void plat_rockchip_pmu_init(void)
650*91f16700Schasinglulu {
651*91f16700Schasinglulu 	uint32_t cpu;
652*91f16700Schasinglulu 
653*91f16700Schasinglulu 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
654*91f16700Schasinglulu 		cpuson_flags[cpu] = 0;
655*91f16700Schasinglulu 
656*91f16700Schasinglulu 	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
657*91f16700Schasinglulu 
658*91f16700Schasinglulu 	/* the warm booting address of cpus */
659*91f16700Schasinglulu 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
660*91f16700Schasinglulu 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
661*91f16700Schasinglulu 		      CPU_BOOT_ADDR_WMASK);
662*91f16700Schasinglulu 
663*91f16700Schasinglulu 	nonboot_cpus_off();
664*91f16700Schasinglulu 
665*91f16700Schasinglulu 	INFO("%s: pd status 0x%x\n",
666*91f16700Schasinglulu 	     __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
667*91f16700Schasinglulu }
668