xref: /rk3399_ARM-atf/plat/rockchip/rk3576/drivers/pmu/pmu.c (revision 036935a8144b9c4b9f95f249ff4384945b846d40)
1*036935a8SXiaoDong Huang // SPDX-License-Identifier: BSD-3-Clause
2*036935a8SXiaoDong Huang /*
3*036935a8SXiaoDong Huang  * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
4*036935a8SXiaoDong Huang  */
5*036935a8SXiaoDong Huang 
6*036935a8SXiaoDong Huang #include <assert.h>
7*036935a8SXiaoDong Huang #include <errno.h>
8*036935a8SXiaoDong Huang 
9*036935a8SXiaoDong Huang #include <arch_helpers.h>
10*036935a8SXiaoDong Huang #include <bl31/bl31.h>
11*036935a8SXiaoDong Huang #include <common/debug.h>
12*036935a8SXiaoDong Huang #include <drivers/console.h>
13*036935a8SXiaoDong Huang #include <drivers/delay_timer.h>
14*036935a8SXiaoDong Huang #include <lib/mmio.h>
15*036935a8SXiaoDong Huang #include <plat/common/platform.h>
16*036935a8SXiaoDong Huang #include <platform_def.h>
17*036935a8SXiaoDong Huang #include <pmu.h>
18*036935a8SXiaoDong Huang 
19*036935a8SXiaoDong Huang #include <cpus_on_fixed_addr.h>
20*036935a8SXiaoDong Huang #include <dmc_rk3576.h>
21*036935a8SXiaoDong Huang #include <plat_pm_helpers.h>
22*036935a8SXiaoDong Huang #include <plat_private.h>
23*036935a8SXiaoDong Huang #include <pm_pd_regs.h>
24*036935a8SXiaoDong Huang #include <secure.h>
25*036935a8SXiaoDong Huang #include <soc.h>
26*036935a8SXiaoDong Huang 
27*036935a8SXiaoDong Huang static struct psram_data_t *psram_sleep_cfg =
28*036935a8SXiaoDong Huang 	(struct psram_data_t *)&sys_sleep_flag_sram;
29*036935a8SXiaoDong Huang 
30*036935a8SXiaoDong Huang struct rk3576_sleep_ddr_data {
31*036935a8SXiaoDong Huang 	uint32_t cru_mode_con, secure_cru_mode;
32*036935a8SXiaoDong Huang 	uint32_t gpio0a_iomux_l, gpio0a_iomux_h, gpio0b_iomux_l;
33*036935a8SXiaoDong Huang 	uint32_t pmu2_bisr_glb_con;
34*036935a8SXiaoDong Huang 	uint32_t pmu2_c0_ack_sel_con0, pmu2_c1_ack_sel_con0, pmu2_c2_ack_sel_con0;
35*036935a8SXiaoDong Huang 	uint32_t pmu2_fast_pwr_con, pmu2_pwrgt_sft_con0;
36*036935a8SXiaoDong Huang 	uint32_t pmu0grf_soc_con0, pmu0grf_soc_con1, pmu0grf_soc_con5;
37*036935a8SXiaoDong Huang 	uint32_t pmu_pd_st, bus_idle_st;
38*036935a8SXiaoDong Huang 	uint32_t sys_sgrf_soc_con0;
39*036935a8SXiaoDong Huang 	uint32_t ddrgrf_cha_con2, ddrgrf_chb_con2;
40*036935a8SXiaoDong Huang };
41*036935a8SXiaoDong Huang 
42*036935a8SXiaoDong Huang static struct rk3576_sleep_ddr_data ddr_data;
43*036935a8SXiaoDong Huang 
44*036935a8SXiaoDong Huang void rockchip_plat_mmu_el3(void)
45*036935a8SXiaoDong Huang {
46*036935a8SXiaoDong Huang #ifdef PLAT_EXTRA_LD_SCRIPT
47*036935a8SXiaoDong Huang 	size_t sram_size;
48*036935a8SXiaoDong Huang 
49*036935a8SXiaoDong Huang 	sram_size = (char *)&__bl31_pmusram_text_end -
50*036935a8SXiaoDong Huang 		    (char *)PMUSRAM_BASE;
51*036935a8SXiaoDong Huang 	mmap_add_region(PMUSRAM_BASE, PMUSRAM_BASE,
52*036935a8SXiaoDong Huang 			sram_size, MT_MEMORY | MT_RO | MT_SECURE);
53*036935a8SXiaoDong Huang 
54*036935a8SXiaoDong Huang 	sram_size = (char *)&__bl31_pmusram_data_end -
55*036935a8SXiaoDong Huang 		    (char *)&__bl31_pmusram_data_start;
56*036935a8SXiaoDong Huang 	mmap_add_region((unsigned long)&__bl31_pmusram_data_start,
57*036935a8SXiaoDong Huang 			(unsigned long)&__bl31_pmusram_data_start,
58*036935a8SXiaoDong Huang 			sram_size, MT_DEVICE | MT_RW | MT_SECURE);
59*036935a8SXiaoDong Huang #endif
60*036935a8SXiaoDong Huang }
61*036935a8SXiaoDong Huang 
62*036935a8SXiaoDong Huang static int check_cpu_wfie(uint32_t cpu)
63*036935a8SXiaoDong Huang {
64*036935a8SXiaoDong Huang 	uint32_t loop = 0;
65*036935a8SXiaoDong Huang 
66*036935a8SXiaoDong Huang 	while ((mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0) & BIT(cpu + 12)) == 0 &&
67*036935a8SXiaoDong Huang 	       (mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) & BIT(cpu)) == 0 &&
68*036935a8SXiaoDong Huang 	       (loop < WFEI_CHECK_LOOP)) {
69*036935a8SXiaoDong Huang 		udelay(1);
70*036935a8SXiaoDong Huang 		loop++;
71*036935a8SXiaoDong Huang 	}
72*036935a8SXiaoDong Huang 
73*036935a8SXiaoDong Huang 	if (loop >= WFEI_CHECK_LOOP) {
74*036935a8SXiaoDong Huang 		WARN("%s: error, cpu%d (0x%x 0x%x)!\n", __func__, cpu,
75*036935a8SXiaoDong Huang 		     mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0),
76*036935a8SXiaoDong Huang 		     mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST));
77*036935a8SXiaoDong Huang 		return -EINVAL;
78*036935a8SXiaoDong Huang 	}
79*036935a8SXiaoDong Huang 
80*036935a8SXiaoDong Huang 	return 0;
81*036935a8SXiaoDong Huang }
82*036935a8SXiaoDong Huang 
83*036935a8SXiaoDong Huang static inline uint32_t cpu_power_domain_st(uint32_t cpu)
84*036935a8SXiaoDong Huang {
85*036935a8SXiaoDong Huang 	return !!(mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) &
86*036935a8SXiaoDong Huang 		  BIT(cpu + 16));
87*036935a8SXiaoDong Huang }
88*036935a8SXiaoDong Huang 
89*036935a8SXiaoDong Huang static int cpu_power_domain_ctr(uint32_t cpu, uint32_t pd_state)
90*036935a8SXiaoDong Huang {
91*036935a8SXiaoDong Huang 	uint32_t loop = 0;
92*036935a8SXiaoDong Huang 	int ret = 0;
93*036935a8SXiaoDong Huang 
94*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu),
95*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(pd_state, 0x1, 0));
96*036935a8SXiaoDong Huang 
97*036935a8SXiaoDong Huang 	dsb();
98*036935a8SXiaoDong Huang 	while ((cpu_power_domain_st(cpu) != pd_state) && (loop < PD_CTR_LOOP)) {
99*036935a8SXiaoDong Huang 		udelay(1);
100*036935a8SXiaoDong Huang 		loop++;
101*036935a8SXiaoDong Huang 	}
102*036935a8SXiaoDong Huang 
103*036935a8SXiaoDong Huang 	if (cpu_power_domain_st(cpu) != pd_state) {
104*036935a8SXiaoDong Huang 		WARN("%s: %d, %d, error!\n", __func__, cpu, pd_state);
105*036935a8SXiaoDong Huang 		ret = -EINVAL;
106*036935a8SXiaoDong Huang 	}
107*036935a8SXiaoDong Huang 
108*036935a8SXiaoDong Huang 	return ret;
109*036935a8SXiaoDong Huang }
110*036935a8SXiaoDong Huang 
111*036935a8SXiaoDong Huang static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
112*036935a8SXiaoDong Huang {
113*036935a8SXiaoDong Huang 	uint32_t val;
114*036935a8SXiaoDong Huang 
115*036935a8SXiaoDong Huang 	if ((mmio_read_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu_id)) & BIT(0)) != 0)
116*036935a8SXiaoDong Huang 		return core_pwr_pd;
117*036935a8SXiaoDong Huang 
118*036935a8SXiaoDong Huang 	val = mmio_read_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id));
119*036935a8SXiaoDong Huang 	if ((val & BIT(pmu_cpu_pm_en)) != 0) {
120*036935a8SXiaoDong Huang 		if ((val & BIT(core_pwr_wfi_int)) != 0)
121*036935a8SXiaoDong Huang 			return core_pwr_wfi_int;
122*036935a8SXiaoDong Huang 		else if ((val & BIT(pmu_cpu_pm_sft_wakeup_en)) != 0)
123*036935a8SXiaoDong Huang 			return core_pwr_wfi_reset;
124*036935a8SXiaoDong Huang 		else
125*036935a8SXiaoDong Huang 			return core_pwr_wfi;
126*036935a8SXiaoDong Huang 	} else {
127*036935a8SXiaoDong Huang 		return -1;
128*036935a8SXiaoDong Huang 	}
129*036935a8SXiaoDong Huang }
130*036935a8SXiaoDong Huang 
131*036935a8SXiaoDong Huang static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
132*036935a8SXiaoDong Huang {
133*036935a8SXiaoDong Huang }
134*036935a8SXiaoDong Huang 
135*036935a8SXiaoDong Huang static int cpus_power_domain_on(uint32_t cpu_id)
136*036935a8SXiaoDong Huang {
137*036935a8SXiaoDong Huang 	uint32_t cfg_info;
138*036935a8SXiaoDong Huang 	/*
139*036935a8SXiaoDong Huang 	 * There are two ways to powering on or off on core.
140*036935a8SXiaoDong Huang 	 * 1) Control it power domain into on or off in PMU_PWRDN_CON reg
141*036935a8SXiaoDong Huang 	 * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
142*036935a8SXiaoDong Huang 	 *	then, if the core enter into wfi, it power domain will be
143*036935a8SXiaoDong Huang 	 *	powered off automatically.
144*036935a8SXiaoDong Huang 	 */
145*036935a8SXiaoDong Huang 
146*036935a8SXiaoDong Huang 	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
147*036935a8SXiaoDong Huang 
148*036935a8SXiaoDong Huang 	if (cfg_info == core_pwr_pd) {
149*036935a8SXiaoDong Huang 		/* disable core_pm cfg */
150*036935a8SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
151*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(0, 0xf, 0));
152*036935a8SXiaoDong Huang 		/* if the cores have be on, power off it firstly */
153*036935a8SXiaoDong Huang 		if (cpu_power_domain_st(cpu_id) == pmu_pd_on)
154*036935a8SXiaoDong Huang 			cpu_power_domain_ctr(cpu_id, pmu_pd_off);
155*036935a8SXiaoDong Huang 
156*036935a8SXiaoDong Huang 		cpu_power_domain_ctr(cpu_id, pmu_pd_on);
157*036935a8SXiaoDong Huang 	} else {
158*036935a8SXiaoDong Huang 		if (cpu_power_domain_st(cpu_id) == pmu_pd_on) {
159*036935a8SXiaoDong Huang 			WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id);
160*036935a8SXiaoDong Huang 			return -EINVAL;
161*036935a8SXiaoDong Huang 		}
162*036935a8SXiaoDong Huang 
163*036935a8SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
164*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(1, 0x1, pmu_cpu_pm_sft_wakeup_en));
165*036935a8SXiaoDong Huang 		dsb();
166*036935a8SXiaoDong Huang 	}
167*036935a8SXiaoDong Huang 
168*036935a8SXiaoDong Huang 	return 0;
169*036935a8SXiaoDong Huang }
170*036935a8SXiaoDong Huang 
171*036935a8SXiaoDong Huang static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
172*036935a8SXiaoDong Huang {
173*036935a8SXiaoDong Huang 	uint32_t core_pm_value;
174*036935a8SXiaoDong Huang 
175*036935a8SXiaoDong Huang 	if (cpu_power_domain_st(cpu_id) == pmu_pd_off)
176*036935a8SXiaoDong Huang 		return 0;
177*036935a8SXiaoDong Huang 
178*036935a8SXiaoDong Huang 	if (pd_cfg == core_pwr_pd) {
179*036935a8SXiaoDong Huang 		if (check_cpu_wfie(cpu_id))
180*036935a8SXiaoDong Huang 			return -EINVAL;
181*036935a8SXiaoDong Huang 
182*036935a8SXiaoDong Huang 		/* disable core_pm cfg */
183*036935a8SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
184*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(0, 0xf, 0));
185*036935a8SXiaoDong Huang 
186*036935a8SXiaoDong Huang 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
187*036935a8SXiaoDong Huang 		cpu_power_domain_ctr(cpu_id, pmu_pd_off);
188*036935a8SXiaoDong Huang 	} else {
189*036935a8SXiaoDong Huang 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
190*036935a8SXiaoDong Huang 
191*036935a8SXiaoDong Huang 		core_pm_value = BIT(pmu_cpu_pm_en) | BIT(pmu_cpu_pm_dis_int);
192*036935a8SXiaoDong Huang 		if (pd_cfg == core_pwr_wfi_int)
193*036935a8SXiaoDong Huang 			core_pm_value |= BIT(pmu_cpu_pm_int_wakeup_en);
194*036935a8SXiaoDong Huang 		else if (pd_cfg == core_pwr_wfi_reset)
195*036935a8SXiaoDong Huang 			core_pm_value |= BIT(pmu_cpu_pm_sft_wakeup_en);
196*036935a8SXiaoDong Huang 
197*036935a8SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
198*036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(core_pm_value, 0xf, 0));
199*036935a8SXiaoDong Huang 		dsb();
200*036935a8SXiaoDong Huang 	}
201*036935a8SXiaoDong Huang 
202*036935a8SXiaoDong Huang 	return 0;
203*036935a8SXiaoDong Huang }
204*036935a8SXiaoDong Huang 
205*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
206*036935a8SXiaoDong Huang {
207*036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
208*036935a8SXiaoDong Huang 
209*036935a8SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
210*036935a8SXiaoDong Huang 	assert(cpuson_flags[cpu_id] == 0);
211*036935a8SXiaoDong Huang 	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
212*036935a8SXiaoDong Huang 	cpuson_entry_point[cpu_id] = entrypoint;
213*036935a8SXiaoDong Huang 	dsb();
214*036935a8SXiaoDong Huang 
215*036935a8SXiaoDong Huang 	cpus_power_domain_on(cpu_id);
216*036935a8SXiaoDong Huang 
217*036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
218*036935a8SXiaoDong Huang }
219*036935a8SXiaoDong Huang 
220*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_off(void)
221*036935a8SXiaoDong Huang {
222*036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
223*036935a8SXiaoDong Huang 
224*036935a8SXiaoDong Huang 	cpus_power_domain_off(cpu_id, core_pwr_wfi);
225*036935a8SXiaoDong Huang 
226*036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
227*036935a8SXiaoDong Huang }
228*036935a8SXiaoDong Huang 
229*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on_finish(void)
230*036935a8SXiaoDong Huang {
231*036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
232*036935a8SXiaoDong Huang 
233*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
234*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 0));
235*036935a8SXiaoDong Huang 
236*036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
237*036935a8SXiaoDong Huang }
238*036935a8SXiaoDong Huang 
239*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_suspend(void)
240*036935a8SXiaoDong Huang {
241*036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
242*036935a8SXiaoDong Huang 
243*036935a8SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
244*036935a8SXiaoDong Huang 	assert(cpuson_flags[cpu_id] == 0);
245*036935a8SXiaoDong Huang 	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
246*036935a8SXiaoDong Huang 	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
247*036935a8SXiaoDong Huang 	dsb();
248*036935a8SXiaoDong Huang 
249*036935a8SXiaoDong Huang 	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
250*036935a8SXiaoDong Huang 
251*036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
252*036935a8SXiaoDong Huang }
253*036935a8SXiaoDong Huang 
254*036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_resume(void)
255*036935a8SXiaoDong Huang {
256*036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
257*036935a8SXiaoDong Huang 
258*036935a8SXiaoDong Huang 	/* Disable core_pm */
259*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
260*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 0));
261*036935a8SXiaoDong Huang 
262*036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
263*036935a8SXiaoDong Huang }
264*036935a8SXiaoDong Huang 
265*036935a8SXiaoDong Huang void nonboot_cpus_off(void)
266*036935a8SXiaoDong Huang {
267*036935a8SXiaoDong Huang 	uint32_t boot_cpu, cpu;
268*036935a8SXiaoDong Huang 
269*036935a8SXiaoDong Huang 	boot_cpu = plat_my_core_pos();
270*036935a8SXiaoDong Huang 
271*036935a8SXiaoDong Huang 	/* turn off noboot cpus */
272*036935a8SXiaoDong Huang 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
273*036935a8SXiaoDong Huang 		if (cpu == boot_cpu)
274*036935a8SXiaoDong Huang 			continue;
275*036935a8SXiaoDong Huang 
276*036935a8SXiaoDong Huang 		cpus_power_domain_off(cpu, core_pwr_pd);
277*036935a8SXiaoDong Huang 	}
278*036935a8SXiaoDong Huang }
279*036935a8SXiaoDong Huang 
280*036935a8SXiaoDong Huang static __pmusramfunc void ddr_resume(void)
281*036935a8SXiaoDong Huang {
282*036935a8SXiaoDong Huang 	uint32_t key_upd_msk =
283*036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pmu_pd_vop) ? 0x3 : 0x7;
284*036935a8SXiaoDong Huang 
285*036935a8SXiaoDong Huang 	/* hptimer is 24M here */
286*036935a8SXiaoDong Huang 	write_cntfrq_el0(24000000);
287*036935a8SXiaoDong Huang 
288*036935a8SXiaoDong Huang 	/* release cpu1~cpu7 to make pmu1_fsm exit */
289*036935a8SXiaoDong Huang 	mmio_write_32(CCI_GRF_BASE + CCIGRF_CON(4), 0xffffffff);
290*036935a8SXiaoDong Huang 	mmio_write_32(LITCORE_GRF_BASE + COREGRF_CPU_CON(1),
291*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x77, 0xff, 4));
292*036935a8SXiaoDong Huang 
293*036935a8SXiaoDong Huang 	/* wait pmu1 fsm over */
294*036935a8SXiaoDong Huang 	while ((mmio_read_32(PMU_BASE + PMU1_PWR_FSM) & 0xf) != 0)
295*036935a8SXiaoDong Huang 		;
296*036935a8SXiaoDong Huang 
297*036935a8SXiaoDong Huang 	/* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */
298*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000);
299*036935a8SXiaoDong Huang 	dsb();
300*036935a8SXiaoDong Huang 
301*036935a8SXiaoDong Huang 	/* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */
302*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000 | key_upd_msk);
303*036935a8SXiaoDong Huang 
304*036935a8SXiaoDong Huang 	/* SOC_STATUS.center/cci_ddr_hash_key_shift_ready */
305*036935a8SXiaoDong Huang 	while (((mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_STATUS) >> 12) & key_upd_msk) != key_upd_msk)
306*036935a8SXiaoDong Huang 		;
307*036935a8SXiaoDong Huang 
308*036935a8SXiaoDong Huang 	/* CCI_BASE.ctrl_override_reg Attr:W1C addrmap strobe */
309*036935a8SXiaoDong Huang 	mmio_setbits_32(CCI_BASE + 0x0, 0x1 << 29);
310*036935a8SXiaoDong Huang 
311*036935a8SXiaoDong Huang 	/* SOC_CON19.vop/center/cci_ddr_hash_key_auto_update_en */
312*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00700070);
313*036935a8SXiaoDong Huang }
314*036935a8SXiaoDong Huang 
315*036935a8SXiaoDong Huang static uint32_t clk_save[CRU_CLKGATE_CON_CNT + PHP_CRU_CLKGATE_CON_CNT +
316*036935a8SXiaoDong Huang 			 SECURE_CRU_CLKGATE_CON_CNT + SECURE_SCRU_CLKGATE_CON_CNT +
317*036935a8SXiaoDong Huang 			 PMU1CRU_CLKGATE_CON_CNT + PMU1SCRU_CLKGATE_CON_CNT];
318*036935a8SXiaoDong Huang 
319*036935a8SXiaoDong Huang void clk_gate_con_disable(void)
320*036935a8SXiaoDong Huang {
321*036935a8SXiaoDong Huang 	int i;
322*036935a8SXiaoDong Huang 
323*036935a8SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++) {
324*036935a8SXiaoDong Huang 		/* Don't open wdt0 clk (cru_gate16[7:8] */
325*036935a8SXiaoDong Huang 		if (i == 16) {
326*036935a8SXiaoDong Huang 			mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
327*036935a8SXiaoDong Huang 				      0xfe7f0000);
328*036935a8SXiaoDong Huang 		} else {
329*036935a8SXiaoDong Huang 			mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
330*036935a8SXiaoDong Huang 				      0xffff0000);
331*036935a8SXiaoDong Huang 		}
332*036935a8SXiaoDong Huang 	}
333*036935a8SXiaoDong Huang 
334*036935a8SXiaoDong Huang 	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++)
335*036935a8SXiaoDong Huang 		mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i), 0xffff0000);
336*036935a8SXiaoDong Huang 
337*036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++)
338*036935a8SXiaoDong Huang 		mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i), 0xffff0000);
339*036935a8SXiaoDong Huang 
340*036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++)
341*036935a8SXiaoDong Huang 		mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i), 0xffff0000);
342*036935a8SXiaoDong Huang 
343*036935a8SXiaoDong Huang 	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++)
344*036935a8SXiaoDong Huang 		mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i), 0xffff0000);
345*036935a8SXiaoDong Huang 
346*036935a8SXiaoDong Huang 	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++)
347*036935a8SXiaoDong Huang 		mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i), 0xffff0000);
348*036935a8SXiaoDong Huang }
349*036935a8SXiaoDong Huang 
350*036935a8SXiaoDong Huang void clk_gate_con_save(void)
351*036935a8SXiaoDong Huang {
352*036935a8SXiaoDong Huang 	int i, j = 0;
353*036935a8SXiaoDong Huang 
354*036935a8SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++)
355*036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i));
356*036935a8SXiaoDong Huang 
357*036935a8SXiaoDong Huang 	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++)
358*036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i));
359*036935a8SXiaoDong Huang 
360*036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++)
361*036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i));
362*036935a8SXiaoDong Huang 
363*036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++)
364*036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i));
365*036935a8SXiaoDong Huang 
366*036935a8SXiaoDong Huang 	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++)
367*036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i));
368*036935a8SXiaoDong Huang 
369*036935a8SXiaoDong Huang 	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++)
370*036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i));
371*036935a8SXiaoDong Huang }
372*036935a8SXiaoDong Huang 
373*036935a8SXiaoDong Huang void clk_gate_con_restore(void)
374*036935a8SXiaoDong Huang {
375*036935a8SXiaoDong Huang 	int i, j = 0;
376*036935a8SXiaoDong Huang 
377*036935a8SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++)
378*036935a8SXiaoDong Huang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
379*036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
380*036935a8SXiaoDong Huang 
381*036935a8SXiaoDong Huang 	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++)
382*036935a8SXiaoDong Huang 		mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i),
383*036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
384*036935a8SXiaoDong Huang 
385*036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++)
386*036935a8SXiaoDong Huang 		mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i),
387*036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
388*036935a8SXiaoDong Huang 
389*036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++)
390*036935a8SXiaoDong Huang 		mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i),
391*036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
392*036935a8SXiaoDong Huang 
393*036935a8SXiaoDong Huang 	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++)
394*036935a8SXiaoDong Huang 		mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i),
395*036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
396*036935a8SXiaoDong Huang 
397*036935a8SXiaoDong Huang 	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++)
398*036935a8SXiaoDong Huang 		mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i),
399*036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
400*036935a8SXiaoDong Huang }
401*036935a8SXiaoDong Huang 
402*036935a8SXiaoDong Huang void pmu_bus_idle_req(uint32_t bus, uint32_t state)
403*036935a8SXiaoDong Huang {
404*036935a8SXiaoDong Huang 	uint32_t wait_cnt = 0;
405*036935a8SXiaoDong Huang 
406*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_SFTCON(bus / 16),
407*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(state, 0x1, bus % 16));
408*036935a8SXiaoDong Huang 
409*036935a8SXiaoDong Huang 	while (pmu_bus_idle_st(bus) != state ||
410*036935a8SXiaoDong Huang 	       pmu_bus_idle_ack(bus) != state) {
411*036935a8SXiaoDong Huang 		if (++wait_cnt > BUS_IDLE_LOOP)
412*036935a8SXiaoDong Huang 			break;
413*036935a8SXiaoDong Huang 		udelay(1);
414*036935a8SXiaoDong Huang 	}
415*036935a8SXiaoDong Huang 
416*036935a8SXiaoDong Huang 	if (wait_cnt > BUS_IDLE_LOOP)
417*036935a8SXiaoDong Huang 		WARN("%s: can't  wait state %d for bus %d (0x%x)\n",
418*036935a8SXiaoDong Huang 		     __func__, state, bus,
419*036935a8SXiaoDong Huang 		     mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST));
420*036935a8SXiaoDong Huang }
421*036935a8SXiaoDong Huang 
422*036935a8SXiaoDong Huang static inline uint32_t pmu_power_domain_st(uint32_t pd)
423*036935a8SXiaoDong Huang {
424*036935a8SXiaoDong Huang 	return mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pd) ?
425*036935a8SXiaoDong Huang 	       pmu_pd_off :
426*036935a8SXiaoDong Huang 	       pmu_pd_on;
427*036935a8SXiaoDong Huang }
428*036935a8SXiaoDong Huang 
429*036935a8SXiaoDong Huang int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
430*036935a8SXiaoDong Huang {
431*036935a8SXiaoDong Huang 	uint32_t loop = 0;
432*036935a8SXiaoDong Huang 	int ret = 0;
433*036935a8SXiaoDong Huang 
434*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(pd / 16),
435*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(pd_state, 0x1, pd % 16));
436*036935a8SXiaoDong Huang 	dsb();
437*036935a8SXiaoDong Huang 
438*036935a8SXiaoDong Huang 	while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
439*036935a8SXiaoDong Huang 		udelay(1);
440*036935a8SXiaoDong Huang 		loop++;
441*036935a8SXiaoDong Huang 	}
442*036935a8SXiaoDong Huang 
443*036935a8SXiaoDong Huang 	if (pmu_power_domain_st(pd) != pd_state) {
444*036935a8SXiaoDong Huang 		WARN("%s: %d, %d, (0x%x) error!\n", __func__, pd, pd_state,
445*036935a8SXiaoDong Huang 		     mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST));
446*036935a8SXiaoDong Huang 		ret = -EINVAL;
447*036935a8SXiaoDong Huang 	}
448*036935a8SXiaoDong Huang 
449*036935a8SXiaoDong Huang 	return ret;
450*036935a8SXiaoDong Huang }
451*036935a8SXiaoDong Huang 
452*036935a8SXiaoDong Huang static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
453*036935a8SXiaoDong Huang {
454*036935a8SXiaoDong Huang 	uint32_t state;
455*036935a8SXiaoDong Huang 
456*036935a8SXiaoDong Huang 	if (pmu_power_domain_st(pd_id) == pd_state)
457*036935a8SXiaoDong Huang 		goto out;
458*036935a8SXiaoDong Huang 
459*036935a8SXiaoDong Huang 	if (pd_state == pmu_pd_on)
460*036935a8SXiaoDong Huang 		pmu_power_domain_ctr(pd_id, pd_state);
461*036935a8SXiaoDong Huang 
462*036935a8SXiaoDong Huang 	state = (pd_state == pmu_pd_off) ? pmu_bus_idle : pmu_bus_active;
463*036935a8SXiaoDong Huang 
464*036935a8SXiaoDong Huang 	switch (pd_id) {
465*036935a8SXiaoDong Huang 	case pmu_pd_npu:
466*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_npusys, state);
467*036935a8SXiaoDong Huang 		break;
468*036935a8SXiaoDong Huang 	case pmu_pd_secure:
469*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_secure, state);
470*036935a8SXiaoDong Huang 		break;
471*036935a8SXiaoDong Huang 	case pmu_pd_nvm:
472*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_nvm, state);
473*036935a8SXiaoDong Huang 		break;
474*036935a8SXiaoDong Huang 	case pmu_pd_sd_gmac:
475*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_gmac, state);
476*036935a8SXiaoDong Huang 		break;
477*036935a8SXiaoDong Huang 	case pmu_pd_audio:
478*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_audio, state);
479*036935a8SXiaoDong Huang 		break;
480*036935a8SXiaoDong Huang 	case pmu_pd_php:
481*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_php, state);
482*036935a8SXiaoDong Huang 		break;
483*036935a8SXiaoDong Huang 	case pmu_pd_subphp:
484*036935a8SXiaoDong Huang 		break;
485*036935a8SXiaoDong Huang 	case pmu_pd_vop:
486*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vop, state);
487*036935a8SXiaoDong Huang 		break;
488*036935a8SXiaoDong Huang 	case pmu_pd_vop_smart:
489*036935a8SXiaoDong Huang 		break;
490*036935a8SXiaoDong Huang 	case pmu_pd_vop_clst:
491*036935a8SXiaoDong Huang 		break;
492*036935a8SXiaoDong Huang 	case pmu_pd_vo1:
493*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vo1, state);
494*036935a8SXiaoDong Huang 		break;
495*036935a8SXiaoDong Huang 	case pmu_pd_vo0:
496*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vo0, state);
497*036935a8SXiaoDong Huang 		break;
498*036935a8SXiaoDong Huang 	case pmu_pd_usb:
499*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_usb, state);
500*036935a8SXiaoDong Huang 		break;
501*036935a8SXiaoDong Huang 	case pmu_pd_vi:
502*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vi, state);
503*036935a8SXiaoDong Huang 		break;
504*036935a8SXiaoDong Huang 	case pmu_pd_vepu0:
505*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vepu0, state);
506*036935a8SXiaoDong Huang 		break;
507*036935a8SXiaoDong Huang 	case pmu_pd_vepu1:
508*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vepu1, state);
509*036935a8SXiaoDong Huang 		break;
510*036935a8SXiaoDong Huang 	case pmu_pd_vdec:
511*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vdec, state);
512*036935a8SXiaoDong Huang 		break;
513*036935a8SXiaoDong Huang 	case pmu_pd_vpu:
514*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vpu, state);
515*036935a8SXiaoDong Huang 		break;
516*036935a8SXiaoDong Huang 	case pmu_pd_nputop:
517*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_nputop, state);
518*036935a8SXiaoDong Huang 		break;
519*036935a8SXiaoDong Huang 	case pmu_pd_npu0:
520*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_npu0, state);
521*036935a8SXiaoDong Huang 		break;
522*036935a8SXiaoDong Huang 	case pmu_pd_npu1:
523*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_npu1, state);
524*036935a8SXiaoDong Huang 		break;
525*036935a8SXiaoDong Huang 	case pmu_pd_gpu:
526*036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_gpu, state);
527*036935a8SXiaoDong Huang 		break;
528*036935a8SXiaoDong Huang 	default:
529*036935a8SXiaoDong Huang 		break;
530*036935a8SXiaoDong Huang 	}
531*036935a8SXiaoDong Huang 
532*036935a8SXiaoDong Huang 	if (pd_state == pmu_pd_off)
533*036935a8SXiaoDong Huang 		pmu_power_domain_ctr(pd_id, pd_state);
534*036935a8SXiaoDong Huang 
535*036935a8SXiaoDong Huang out:
536*036935a8SXiaoDong Huang 	return 0;
537*036935a8SXiaoDong Huang }
538*036935a8SXiaoDong Huang 
539*036935a8SXiaoDong Huang static void pmu_power_domains_suspend(void)
540*036935a8SXiaoDong Huang {
541*036935a8SXiaoDong Huang 	ddr_data.pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST);
542*036935a8SXiaoDong Huang 	ddr_data.bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST);
543*036935a8SXiaoDong Huang 	ddr_data.pmu2_pwrgt_sft_con0 = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0));
544*036935a8SXiaoDong Huang 
545*036935a8SXiaoDong Huang 	qos_save();
546*036935a8SXiaoDong Huang 
547*036935a8SXiaoDong Huang 	pd_usb2phy_save();
548*036935a8SXiaoDong Huang 
549*036935a8SXiaoDong Huang 	if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0)
550*036935a8SXiaoDong Huang 		pd_php_save();
551*036935a8SXiaoDong Huang }
552*036935a8SXiaoDong Huang 
553*036935a8SXiaoDong Huang static void pmu_power_domains_resume(void)
554*036935a8SXiaoDong Huang {
555*036935a8SXiaoDong Huang 	int i;
556*036935a8SXiaoDong Huang 
557*036935a8SXiaoDong Huang 	for (i = 0; i < pmu_pd_id_max; i++) {
558*036935a8SXiaoDong Huang 		/* vop smart/clst pd is not controlled by pmu */
559*036935a8SXiaoDong Huang 		if (i == pmu_pd_vop_smart || i == pmu_pd_vop_clst)
560*036935a8SXiaoDong Huang 			continue;
561*036935a8SXiaoDong Huang 
562*036935a8SXiaoDong Huang 		pmu_set_power_domain(i, !!(ddr_data.pmu_pd_st & BIT(i)));
563*036935a8SXiaoDong Huang 	}
564*036935a8SXiaoDong Huang 
565*036935a8SXiaoDong Huang 	/* restore vop smart/clst pd of pmu2_pwrgt_sft_con0 */
566*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0),
567*036935a8SXiaoDong Huang 		      0x30000000 | ddr_data.pmu2_pwrgt_sft_con0);
568*036935a8SXiaoDong Huang 
569*036935a8SXiaoDong Huang 	for (i = pmu_bus_id_max - 1; i >= 0; i--)
570*036935a8SXiaoDong Huang 		pmu_bus_idle_req(i, !!(ddr_data.bus_idle_st & BIT(i)));
571*036935a8SXiaoDong Huang 
572*036935a8SXiaoDong Huang 	if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0)
573*036935a8SXiaoDong Huang 		pd_php_restore();
574*036935a8SXiaoDong Huang 
575*036935a8SXiaoDong Huang 	pd_usb2phy_restore();
576*036935a8SXiaoDong Huang 
577*036935a8SXiaoDong Huang 	qos_restore();
578*036935a8SXiaoDong Huang }
579*036935a8SXiaoDong Huang 
580*036935a8SXiaoDong Huang static void ddr_sleep_config(void)
581*036935a8SXiaoDong Huang {
582*036935a8SXiaoDong Huang 	ddr_data.ddrgrf_cha_con2 =
583*036935a8SXiaoDong Huang 		mmio_read_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2));
584*036935a8SXiaoDong Huang 	ddr_data.ddrgrf_chb_con2 =
585*036935a8SXiaoDong Huang 		mmio_read_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2));
586*036935a8SXiaoDong Huang 
587*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2), 0x0a000a00);
588*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2), 0x0a000a00);
589*036935a8SXiaoDong Huang }
590*036935a8SXiaoDong Huang 
591*036935a8SXiaoDong Huang static void ddr_sleep_config_restore(void)
592*036935a8SXiaoDong Huang {
593*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2),
594*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.ddrgrf_cha_con2));
595*036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2),
596*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.ddrgrf_chb_con2));
597*036935a8SXiaoDong Huang }
598*036935a8SXiaoDong Huang 
599*036935a8SXiaoDong Huang static void sleep_pin_config(void)
600*036935a8SXiaoDong Huang {
601*036935a8SXiaoDong Huang 	/* pwr0 sleep: gpio0_a3 */
602*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1),
603*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x7, 0xf, 0));
604*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0),
605*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0x1, 7));
606*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
607*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(9, 0xfu, 12));
608*036935a8SXiaoDong Huang }
609*036935a8SXiaoDong Huang 
610*036935a8SXiaoDong Huang static void pmu_sleep_config(void)
611*036935a8SXiaoDong Huang {
612*036935a8SXiaoDong Huang 	uint32_t pmu1_wkup_int_con;
613*036935a8SXiaoDong Huang 	uint32_t pmu1_pwr_con, pmu1_ddr_pwr_con, pmu1cru_pwr_con, pmu1_pll_pd_con;
614*036935a8SXiaoDong Huang 	uint32_t pmu2_bus_idle_con[2], pmu2_pwr_gt_con[2];
615*036935a8SXiaoDong Huang 	uint32_t key_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_vop) ? 0x3 : 0x7;
616*036935a8SXiaoDong Huang 	uint32_t fw_lkp_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_npu) ? 0x3 : 0x7;
617*036935a8SXiaoDong Huang 	uint32_t fw_ddr_upd_msk = key_upd_msk;
618*036935a8SXiaoDong Huang 	uint32_t pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST);
619*036935a8SXiaoDong Huang 	uint32_t bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST);
620*036935a8SXiaoDong Huang 
621*036935a8SXiaoDong Huang 	ddr_data.pmu2_bisr_glb_con = mmio_read_32(PMU_BASE + PMU2_BISR_GLB_CON);
622*036935a8SXiaoDong Huang 
623*036935a8SXiaoDong Huang 	ddr_data.pmu2_fast_pwr_con =
624*036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_FAST_POWER_CON);
625*036935a8SXiaoDong Huang 
626*036935a8SXiaoDong Huang 	ddr_data.pmu2_c0_ack_sel_con0 =
627*036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0));
628*036935a8SXiaoDong Huang 	ddr_data.pmu2_c1_ack_sel_con0 =
629*036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0));
630*036935a8SXiaoDong Huang 	ddr_data.pmu2_c2_ack_sel_con0 =
631*036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0));
632*036935a8SXiaoDong Huang 	ddr_data.pmu0grf_soc_con5 =
633*036935a8SXiaoDong Huang 		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5));
634*036935a8SXiaoDong Huang 
635*036935a8SXiaoDong Huang 	/* set tsadc_shut_m0 pin iomux to gpio */
636*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
637*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 4));
638*036935a8SXiaoDong Huang 
639*036935a8SXiaoDong Huang 	pmu1_wkup_int_con =
640*036935a8SXiaoDong Huang 		BIT(pmu_wkup_cpu0_int) |
641*036935a8SXiaoDong Huang 		BIT(pmu_wkup_gpio0_int);
642*036935a8SXiaoDong Huang 
643*036935a8SXiaoDong Huang 	pmu1_pwr_con =
644*036935a8SXiaoDong Huang 		BIT(pmu_powermode_en) |
645*036935a8SXiaoDong Huang 		/* BIT(pmu_scu0_byp) | */
646*036935a8SXiaoDong Huang 		/* BIT(pmu_scu1_byp) | */
647*036935a8SXiaoDong Huang 		/* BIT(pmu_cci_byp) | */
648*036935a8SXiaoDong Huang 		/* BIT(pmu_bus_byp) | */
649*036935a8SXiaoDong Huang 		/* BIT(pmu_ddr_byp) | */
650*036935a8SXiaoDong Huang 		/* BIT(pmu_pwrgt_byp) | */
651*036935a8SXiaoDong Huang 		/* BIT(pmu_cru_byp) | */
652*036935a8SXiaoDong Huang 		BIT(pmu_qch_byp) |
653*036935a8SXiaoDong Huang 		/* BIT(pmu_wfi_byp) | */
654*036935a8SXiaoDong Huang 		BIT(pmu_slp_cnt_en);
655*036935a8SXiaoDong Huang 
656*036935a8SXiaoDong Huang 	pmu1_ddr_pwr_con = 0;
657*036935a8SXiaoDong Huang 
658*036935a8SXiaoDong Huang 	pmu1_pll_pd_con =
659*036935a8SXiaoDong Huang 		BIT(pmu_bpll_pd_en) |
660*036935a8SXiaoDong Huang 		BIT(pmu_lpll_pd_en) |
661*036935a8SXiaoDong Huang 		BIT(pmu_spll_pd_en) |
662*036935a8SXiaoDong Huang 		BIT(pmu_gpll_pd_en) |
663*036935a8SXiaoDong Huang 		BIT(pmu_cpll_pd_en) |
664*036935a8SXiaoDong Huang 		BIT(pmu_ppll_pd_en) |
665*036935a8SXiaoDong Huang 		BIT(pmu_aupll_pd_en) |
666*036935a8SXiaoDong Huang 		BIT(pmu_vpll_pd_en);
667*036935a8SXiaoDong Huang 
668*036935a8SXiaoDong Huang 	pmu1cru_pwr_con =
669*036935a8SXiaoDong Huang 		BIT(pmu_alive_osc_mode_en) |
670*036935a8SXiaoDong Huang 		BIT(pmu_io_sleep_en) |
671*036935a8SXiaoDong Huang 		BIT(pmu_power_off_en);
672*036935a8SXiaoDong Huang 
673*036935a8SXiaoDong Huang 	pmu2_bus_idle_con[0] = 0xffff & ~(bus_idle_st & 0xffff);
674*036935a8SXiaoDong Huang 	pmu2_bus_idle_con[1] = 0x3fff & ~(bus_idle_st >> 16);
675*036935a8SXiaoDong Huang 
676*036935a8SXiaoDong Huang 	pmu2_pwr_gt_con[0] = 0xffff & ~(pmu_pd_st & 0xffff);
677*036935a8SXiaoDong Huang 	pmu2_pwr_gt_con[1] = 0x03ff & ~(pmu_pd_st >> 16);
678*036935a8SXiaoDong Huang 
679*036935a8SXiaoDong Huang 	pmu2_pwr_gt_con[0] &=
680*036935a8SXiaoDong Huang 		~(BIT(pmu_pd_secure) |
681*036935a8SXiaoDong Huang 		  BIT(pmu_pd_bus) |
682*036935a8SXiaoDong Huang 		  BIT(pmu_pd_center) |
683*036935a8SXiaoDong Huang 		  BIT(pmu_pd_ddr));
684*036935a8SXiaoDong Huang 
685*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0x00030003);
686*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON0, 0x03ff0000);
687*036935a8SXiaoDong Huang 
688*036935a8SXiaoDong Huang 	/* disable repair */
689*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON, 0x00010000);
690*036935a8SXiaoDong Huang 
691*036935a8SXiaoDong Huang 	/* disable ddr_hash_key update.
692*036935a8SXiaoDong Huang 	 * enable disable ddr_hash_key auto update.
693*036935a8SXiaoDong Huang 	 * wait ddr_hash_key auto update.
694*036935a8SXiaoDong Huang 	 */
695*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19),
696*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(key_upd_msk, 0x7, 8));
697*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1,
698*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(fw_lkp_upd_msk, 0x7, 10));
699*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1,
700*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(fw_ddr_upd_msk, 0x7u, 13));
701*036935a8SXiaoDong Huang 
702*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_PMIC_STABLE_CNT_THRES, 24000 * 5);
703*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_OSC_STABLE_CNT_THRES, 24000 * 5);
704*036935a8SXiaoDong Huang 
705*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_OSC_STABLE_CNT_THRESH, 24000 * 5);
706*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_STABLE_CNT_THRESH, 24000 * 5);
707*036935a8SXiaoDong Huang 
708*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_SLEEP_CNT_THRESH, 24000 * 15);
709*036935a8SXiaoDong Huang 
710*036935a8SXiaoDong Huang 	/* Pmu's clk has switched to 24M back When pmu FSM counts
711*036935a8SXiaoDong Huang 	 * the follow counters, so we should use 24M to calculate
712*036935a8SXiaoDong Huang 	 * these counters.
713*036935a8SXiaoDong Huang 	 */
714*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_WAKEUP_RST_CLR_CNT_THRES, 12000);
715*036935a8SXiaoDong Huang 
716*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_WAKEUP_RST_CLR_CNT_THRESH, 12000);
717*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PLL_LOCK_CNT_THRESH, 12000);
718*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PWM_SWITCH_CNT_THRESH,
719*036935a8SXiaoDong Huang 		      24000 * 2);
720*036935a8SXiaoDong Huang 
721*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_PWRUP_CNT_THRESH, 0);
722*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_PWRDN_CNT_THRESH, 0);
723*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_STABLE_CNT_THRESH, 0);
724*036935a8SXiaoDong Huang 
725*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_0, 0);
726*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_0, 0);
727*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_1, 0);
728*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_1, 0);
729*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_2, 0);
730*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_2, 0);
731*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON, 0xffff0007);
732*036935a8SXiaoDong Huang 
733*036935a8SXiaoDong Huang 	/* pmu_clst_idle_con */
734*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0007);
735*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CLUSTER1_IDLE_CON, 0xffff0007);
736*036935a8SXiaoDong Huang 
737*036935a8SXiaoDong Huang 	/* pmu_scu_pwr_con */
738*036935a8SXiaoDong Huang 	/* L2's flush and idle by hardware, so need to enable wfil2 bypass */
739*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff020f);
740*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU1_PWR_CON, 0xffff020f);
741*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_AUTO_PWR_CON, 0x00070000);
742*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU1_AUTO_PWR_CON, 0x00070000);
743*036935a8SXiaoDong Huang 
744*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0009);
745*036935a8SXiaoDong Huang 
746*036935a8SXiaoDong Huang 	/* pmu_int_msk_con */
747*036935a8SXiaoDong Huang 	/* mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, BITS_WITH_WMASK(1, 0x1, 0)); */
748*036935a8SXiaoDong Huang 
749*036935a8SXiaoDong Huang 	/* pmu_pwr_con */
750*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PWR_CON, WITH_16BITS_WMSK(pmu1_pwr_con));
751*036935a8SXiaoDong Huang 
752*036935a8SXiaoDong Huang 	/* pmu_cru_pwr_conx */
753*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), WITH_16BITS_WMSK(pmu1cru_pwr_con));
754*036935a8SXiaoDong Huang 
755*036935a8SXiaoDong Huang 	/* pmu_ddr_pwr_con */
756*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_DDR_RET_CON(1), 0xffff0000);
757*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), WITH_16BITS_WMSK(pmu1_ddr_pwr_con));
758*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), WITH_16BITS_WMSK(pmu1_ddr_pwr_con));
759*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0x03ff03ff);
760*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0x03ff03ff);
761*036935a8SXiaoDong Huang 
762*036935a8SXiaoDong Huang 	/* pll_pd */
763*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), WITH_16BITS_WMSK(pmu1_pll_pd_con));
764*036935a8SXiaoDong Huang 
765*036935a8SXiaoDong Huang 	/* bus idle */
766*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), WITH_16BITS_WMSK(pmu2_bus_idle_con[0]));
767*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), WITH_16BITS_WMSK(pmu2_bus_idle_con[1]));
768*036935a8SXiaoDong Huang 
769*036935a8SXiaoDong Huang 	/* power gate */
770*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), WITH_16BITS_WMSK(pmu2_pwr_gt_con[0]));
771*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), WITH_16BITS_WMSK(pmu2_pwr_gt_con[1]));
772*036935a8SXiaoDong Huang 
773*036935a8SXiaoDong Huang 	/* vol gate */
774*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0031);
775*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0200);
776*036935a8SXiaoDong Huang 
777*036935a8SXiaoDong Huang 	/* wakeup source */
778*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, pmu1_wkup_int_con);
779*036935a8SXiaoDong Huang 
780*036935a8SXiaoDong Huang 	/* ppll clamp */
781*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 0x00400040);
782*036935a8SXiaoDong Huang 
783*036935a8SXiaoDong Huang 	/* usbphy clamp */
784*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5),
785*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x9, 0x9, 2));
786*036935a8SXiaoDong Huang 
787*036935a8SXiaoDong Huang 	/* big core pwr ack bypass */
788*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0), 0x01000100);
789*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0), 0x01000100);
790*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0), 0x01000100);
791*036935a8SXiaoDong Huang }
792*036935a8SXiaoDong Huang 
793*036935a8SXiaoDong Huang static void pmu_sleep_restore(void)
794*036935a8SXiaoDong Huang {
795*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_INFO_TX_CON, 0xffff0000);
796*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_DEBUG_INFO_SEL, 0xffff0000);
797*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0000);
798*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff0000);
799*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0000);
800*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, 0xffff0000);
801*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PWR_CON, 0xffff0000);
802*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), 0xffff0000);
803*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), 0xffff0000);
804*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), 0xffff0000);
805*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0xffff0000);
806*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0xffff0000);
807*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), 0xffff0000);
808*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), 0xffff0000);
809*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), 0xffff0000);
810*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), 0xffff0000);
811*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), 0xffff0000);
812*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0000);
813*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0000);
814*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0xffff0000);
815*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, 0);
816*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON,
817*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_fast_pwr_con));
818*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON,
819*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_bisr_glb_con));
820*036935a8SXiaoDong Huang 
821*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0),
822*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_c0_ack_sel_con0));
823*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0),
824*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_c1_ack_sel_con0));
825*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0),
826*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_c2_ack_sel_con0));
827*036935a8SXiaoDong Huang 
828*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5),
829*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con5));
830*036935a8SXiaoDong Huang }
831*036935a8SXiaoDong Huang 
832*036935a8SXiaoDong Huang static void secure_watchdog_disable(void)
833*036935a8SXiaoDong Huang {
834*036935a8SXiaoDong Huang 	ddr_data.sys_sgrf_soc_con0 =
835*036935a8SXiaoDong Huang 		mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0));
836*036935a8SXiaoDong Huang 
837*036935a8SXiaoDong Huang 	/* pause wdt_s */
838*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0),
839*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, 14));
840*036935a8SXiaoDong Huang }
841*036935a8SXiaoDong Huang 
842*036935a8SXiaoDong Huang static void secure_watchdog_restore(void)
843*036935a8SXiaoDong Huang {
844*036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0),
845*036935a8SXiaoDong Huang 		      ddr_data.sys_sgrf_soc_con0 |
846*036935a8SXiaoDong Huang 		      BITS_WMSK(0x1, 14));
847*036935a8SXiaoDong Huang 
848*036935a8SXiaoDong Huang 	if (mmio_read_32(WDT_S_BASE + WDT_CR) & WDT_EN)
849*036935a8SXiaoDong Huang 		mmio_write_32(WDT_S_BASE + WDT_CRR, 0x76);
850*036935a8SXiaoDong Huang }
851*036935a8SXiaoDong Huang 
852*036935a8SXiaoDong Huang static void soc_sleep_config(void)
853*036935a8SXiaoDong Huang {
854*036935a8SXiaoDong Huang 	ddr_data.pmu0grf_soc_con0 =
855*036935a8SXiaoDong Huang 		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0));
856*036935a8SXiaoDong Huang 	ddr_data.pmu0grf_soc_con1 =
857*036935a8SXiaoDong Huang 		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1));
858*036935a8SXiaoDong Huang 
859*036935a8SXiaoDong Huang 	ddr_data.gpio0a_iomux_l =
860*036935a8SXiaoDong Huang 		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L);
861*036935a8SXiaoDong Huang 	ddr_data.gpio0a_iomux_h =
862*036935a8SXiaoDong Huang 		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H);
863*036935a8SXiaoDong Huang 	ddr_data.gpio0b_iomux_l =
864*036935a8SXiaoDong Huang 		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L);
865*036935a8SXiaoDong Huang 
866*036935a8SXiaoDong Huang 	sleep_pin_config();
867*036935a8SXiaoDong Huang 	pmu_sleep_config();
868*036935a8SXiaoDong Huang 	ddr_sleep_config();
869*036935a8SXiaoDong Huang 	secure_watchdog_disable();
870*036935a8SXiaoDong Huang }
871*036935a8SXiaoDong Huang 
872*036935a8SXiaoDong Huang static void soc_sleep_restore(void)
873*036935a8SXiaoDong Huang {
874*036935a8SXiaoDong Huang 	secure_watchdog_restore();
875*036935a8SXiaoDong Huang 	ddr_sleep_config_restore();
876*036935a8SXiaoDong Huang 	pmu_sleep_restore();
877*036935a8SXiaoDong Huang 
878*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
879*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_l));
880*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H,
881*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_h));
882*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L,
883*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.gpio0b_iomux_l));
884*036935a8SXiaoDong Huang 
885*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1),
886*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con1));
887*036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0),
888*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con0));
889*036935a8SXiaoDong Huang }
890*036935a8SXiaoDong Huang 
891*036935a8SXiaoDong Huang static void pm_pll_suspend(void)
892*036935a8SXiaoDong Huang {
893*036935a8SXiaoDong Huang 	ddr_data.cru_mode_con = mmio_read_32(CRU_BASE + 0x280);
894*036935a8SXiaoDong Huang 	ddr_data.secure_cru_mode = mmio_read_32(SECURE_CRU_BASE + 0x4280);
895*036935a8SXiaoDong Huang 
896*036935a8SXiaoDong Huang 	/* bpll gpll vpll aupll cpll spll switch to slow mode */
897*036935a8SXiaoDong Huang 	mmio_write_32(CRU_BASE + 0x280, 0x03ff0000);
898*036935a8SXiaoDong Huang 	mmio_write_32(SECURE_CRU_BASE + 0x4280, 0x00030000);
899*036935a8SXiaoDong Huang 
900*036935a8SXiaoDong Huang 	/* hclk_pmu_cm0_root_i_sel to 24M */
901*036935a8SXiaoDong Huang 	mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKSEL_CON(4),
902*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x3, 0x3, 2));
903*036935a8SXiaoDong Huang }
904*036935a8SXiaoDong Huang 
905*036935a8SXiaoDong Huang static void pm_pll_restore(void)
906*036935a8SXiaoDong Huang {
907*036935a8SXiaoDong Huang 	mmio_write_32(CRU_BASE + 0x280, WITH_16BITS_WMSK(ddr_data.cru_mode_con));
908*036935a8SXiaoDong Huang 	mmio_write_32(SECURE_CRU_BASE + 0x4280,
909*036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.secure_cru_mode));
910*036935a8SXiaoDong Huang }
911*036935a8SXiaoDong Huang 
912*036935a8SXiaoDong Huang int rockchip_soc_sys_pwr_dm_suspend(void)
913*036935a8SXiaoDong Huang {
914*036935a8SXiaoDong Huang 	psram_sleep_cfg->pm_flag &= ~PM_WARM_BOOT_BIT;
915*036935a8SXiaoDong Huang 
916*036935a8SXiaoDong Huang 	clk_gate_con_save();
917*036935a8SXiaoDong Huang 	clk_gate_con_disable();
918*036935a8SXiaoDong Huang 	dmc_save();
919*036935a8SXiaoDong Huang 	pmu_power_domains_suspend();
920*036935a8SXiaoDong Huang 	soc_sleep_config();
921*036935a8SXiaoDong Huang 	pm_pll_suspend();
922*036935a8SXiaoDong Huang 	pd_core_save();
923*036935a8SXiaoDong Huang 
924*036935a8SXiaoDong Huang 	return 0;
925*036935a8SXiaoDong Huang }
926*036935a8SXiaoDong Huang 
927*036935a8SXiaoDong Huang int rockchip_soc_sys_pwr_dm_resume(void)
928*036935a8SXiaoDong Huang {
929*036935a8SXiaoDong Huang 	pd_core_restore();
930*036935a8SXiaoDong Huang 	pm_pll_restore();
931*036935a8SXiaoDong Huang 	soc_sleep_restore();
932*036935a8SXiaoDong Huang 	pmu_power_domains_resume();
933*036935a8SXiaoDong Huang 	plat_rockchip_gic_cpuif_enable();
934*036935a8SXiaoDong Huang 	dmc_restore();
935*036935a8SXiaoDong Huang 	clk_gate_con_restore();
936*036935a8SXiaoDong Huang 
937*036935a8SXiaoDong Huang 	psram_sleep_cfg->pm_flag |= PM_WARM_BOOT_BIT;
938*036935a8SXiaoDong Huang 
939*036935a8SXiaoDong Huang 	return 0;
940*036935a8SXiaoDong Huang }
941*036935a8SXiaoDong Huang 
942*036935a8SXiaoDong Huang void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(const
943*036935a8SXiaoDong Huang 					      psci_power_state_t *target_state)
944*036935a8SXiaoDong Huang {
945*036935a8SXiaoDong Huang 	psci_power_down_wfi();
946*036935a8SXiaoDong Huang 	/* should never reach here */
947*036935a8SXiaoDong Huang 	panic();
948*036935a8SXiaoDong Huang }
949*036935a8SXiaoDong Huang 
950*036935a8SXiaoDong Huang void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
951*036935a8SXiaoDong Huang {
952*036935a8SXiaoDong Huang 	psci_power_down_wfi();
953*036935a8SXiaoDong Huang 	/* should never reach here */
954*036935a8SXiaoDong Huang 	panic();
955*036935a8SXiaoDong Huang }
956*036935a8SXiaoDong Huang 
957*036935a8SXiaoDong Huang static int rockchip_reboot_is_rbrom(void)
958*036935a8SXiaoDong Huang {
959*036935a8SXiaoDong Huang 	return mmio_read_32(PMU0_GRF_BASE + PMU0GRF_OS_REG(16)) ==
960*036935a8SXiaoDong Huang 	       BOOT_BROM_DOWNLOAD;
961*036935a8SXiaoDong Huang }
962*036935a8SXiaoDong Huang 
963*036935a8SXiaoDong Huang static void rockchip_soc_soft_reset_check_rstout(void)
964*036935a8SXiaoDong Huang {
965*036935a8SXiaoDong Huang 	/*
966*036935a8SXiaoDong Huang 	 * Maskrom enter maskrom-usb mode according to os_reg0 which
967*036935a8SXiaoDong Huang 	 * will be reset by NPOR. So disable tsadc_shut_m0 if we want
968*036935a8SXiaoDong Huang 	 * to maskrom-usb mode.
969*036935a8SXiaoDong Huang 	 */
970*036935a8SXiaoDong Huang 	if (rockchip_reboot_is_rbrom() != 0) {
971*036935a8SXiaoDong Huang 		/* write BOOT_BROM_DOWNLOAD to os_reg0 */
972*036935a8SXiaoDong Huang 		mmio_write_32(PMU1_GRF_BASE + PMU1GRF_OS_REG(0), BOOT_BROM_DOWNLOAD);
973*036935a8SXiaoDong Huang 
974*036935a8SXiaoDong Huang 		/* disable first/tsadc/wdt reset output */
975*036935a8SXiaoDong Huang 		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(0), 0x00070000);
976*036935a8SXiaoDong Huang 
977*036935a8SXiaoDong Huang 		/* clear reset hold */
978*036935a8SXiaoDong Huang 		mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(1), 0xffff0000);
979*036935a8SXiaoDong Huang 		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(16), 0xffff0000);
980*036935a8SXiaoDong Huang 		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(17), 0xffff0000);
981*036935a8SXiaoDong Huang 	}
982*036935a8SXiaoDong Huang }
983*036935a8SXiaoDong Huang 
984*036935a8SXiaoDong Huang void __dead2 rockchip_soc_soft_reset(void)
985*036935a8SXiaoDong Huang {
986*036935a8SXiaoDong Huang 	rockchip_soc_soft_reset_check_rstout();
987*036935a8SXiaoDong Huang 
988*036935a8SXiaoDong Huang 	/* pll slow mode */
989*036935a8SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_MODE_CON, 0x003f0000);
990*036935a8SXiaoDong Huang 
991*036935a8SXiaoDong Huang 	dsb();
992*036935a8SXiaoDong Huang 	isb();
993*036935a8SXiaoDong Huang 
994*036935a8SXiaoDong Huang 	INFO("system reset......\n");
995*036935a8SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL);
996*036935a8SXiaoDong Huang 
997*036935a8SXiaoDong Huang 	/*
998*036935a8SXiaoDong Huang 	 * Maybe the HW needs some times to reset the system,
999*036935a8SXiaoDong Huang 	 * so we do not hope the core to execute valid codes.
1000*036935a8SXiaoDong Huang 	 */
1001*036935a8SXiaoDong Huang 	psci_power_down_wfi();
1002*036935a8SXiaoDong Huang 	/* should never reach here */
1003*036935a8SXiaoDong Huang 	panic();
1004*036935a8SXiaoDong Huang }
1005*036935a8SXiaoDong Huang 
1006*036935a8SXiaoDong Huang void __dead2 rockchip_soc_system_off(void)
1007*036935a8SXiaoDong Huang {
1008*036935a8SXiaoDong Huang 	INFO("system poweroff......\n");
1009*036935a8SXiaoDong Huang 
1010*036935a8SXiaoDong Huang 	/* gpio0_a3 config output */
1011*036935a8SXiaoDong Huang 	mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DDR_L,
1012*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, 3));
1013*036935a8SXiaoDong Huang 
1014*036935a8SXiaoDong Huang 	/* gpio0_a3 config output high level */
1015*036935a8SXiaoDong Huang 	mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DR_L,
1016*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, 3));
1017*036935a8SXiaoDong Huang 	dsb();
1018*036935a8SXiaoDong Huang 
1019*036935a8SXiaoDong Huang 	/*
1020*036935a8SXiaoDong Huang 	 * Maybe the HW needs some times to reset the system,
1021*036935a8SXiaoDong Huang 	 * so we do not hope the core to execute valid codes.
1022*036935a8SXiaoDong Huang 	 */
1023*036935a8SXiaoDong Huang 	psci_power_down_wfi();
1024*036935a8SXiaoDong Huang 	/* should never reach here */
1025*036935a8SXiaoDong Huang 	panic();
1026*036935a8SXiaoDong Huang }
1027*036935a8SXiaoDong Huang 
1028*036935a8SXiaoDong Huang static void rockchip_pmu_pd_repair_init(void)
1029*036935a8SXiaoDong Huang {
1030*036935a8SXiaoDong Huang 	INFO("enable memory repair\n");
1031*036935a8SXiaoDong Huang 	/* Enable gpu and npu repair */
1032*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BISR_PDGEN_CON(1),
1033*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0xf, 0xf, 6));
1034*036935a8SXiaoDong Huang }
1035*036935a8SXiaoDong Huang 
1036*036935a8SXiaoDong Huang void plat_rockchip_pmu_init(void)
1037*036935a8SXiaoDong Huang {
1038*036935a8SXiaoDong Huang 	int cpu;
1039*036935a8SXiaoDong Huang 
1040*036935a8SXiaoDong Huang 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
1041*036935a8SXiaoDong Huang 		cpuson_flags[cpu] = 0;
1042*036935a8SXiaoDong Huang 
1043*036935a8SXiaoDong Huang 	psram_sleep_cfg->sp = PSRAM_SP_TOP;
1044*036935a8SXiaoDong Huang 	psram_sleep_cfg->ddr_func = (uint64_t)ddr_resume;
1045*036935a8SXiaoDong Huang 	psram_sleep_cfg->ddr_data = 0;
1046*036935a8SXiaoDong Huang 	psram_sleep_cfg->ddr_flag = 0;
1047*036935a8SXiaoDong Huang 	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
1048*036935a8SXiaoDong Huang 	psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT;
1049*036935a8SXiaoDong Huang 
1050*036935a8SXiaoDong Huang 	nonboot_cpus_off();
1051*036935a8SXiaoDong Huang 
1052*036935a8SXiaoDong Huang 	/*
1053*036935a8SXiaoDong Huang 	 * When perform idle operation, corresponding clock can be
1054*036935a8SXiaoDong Huang 	 * opened or gated automatically.
1055*036935a8SXiaoDong Huang 	 */
1056*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(0), 0xffffffff);
1057*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(1), 0xffffffff);
1058*036935a8SXiaoDong Huang 
1059*036935a8SXiaoDong Huang 	/* remap pmusram to 0x00000000 */
1060*036935a8SXiaoDong Huang 	mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(2), BITS_WITH_WMASK(1, 0x3, 0));
1061*036935a8SXiaoDong Huang 
1062*036935a8SXiaoDong Huang 	/* enable power off VD_NPU by hrdware */
1063*036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0),
1064*036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x1, 0x1, 0));
1065*036935a8SXiaoDong Huang 
1066*036935a8SXiaoDong Huang 	rockchip_pmu_pd_repair_init();
1067*036935a8SXiaoDong Huang 
1068*036935a8SXiaoDong Huang 	pm_reg_rgns_init();
1069*036935a8SXiaoDong Huang }
1070