xref: /rk3399_ARM-atf/plat/rockchip/rk3576/drivers/pmu/pmu.c (revision 1ed77d1bf4ce0219b522d601719197ef43fbf140)
1036935a8SXiaoDong Huang // SPDX-License-Identifier: BSD-3-Clause
2036935a8SXiaoDong Huang /*
3036935a8SXiaoDong Huang  * Copyright (c) 2025, Rockchip Electronics Co., Ltd.
4036935a8SXiaoDong Huang  */
5036935a8SXiaoDong Huang 
6036935a8SXiaoDong Huang #include <assert.h>
7036935a8SXiaoDong Huang #include <errno.h>
8036935a8SXiaoDong Huang 
9036935a8SXiaoDong Huang #include <arch_helpers.h>
10036935a8SXiaoDong Huang #include <bl31/bl31.h>
11036935a8SXiaoDong Huang #include <common/debug.h>
12036935a8SXiaoDong Huang #include <drivers/console.h>
13036935a8SXiaoDong Huang #include <drivers/delay_timer.h>
14036935a8SXiaoDong Huang #include <lib/mmio.h>
15036935a8SXiaoDong Huang #include <plat/common/platform.h>
16036935a8SXiaoDong Huang #include <platform_def.h>
17036935a8SXiaoDong Huang #include <pmu.h>
18036935a8SXiaoDong Huang 
19036935a8SXiaoDong Huang #include <cpus_on_fixed_addr.h>
20036935a8SXiaoDong Huang #include <dmc_rk3576.h>
21036935a8SXiaoDong Huang #include <plat_pm_helpers.h>
22036935a8SXiaoDong Huang #include <plat_private.h>
23036935a8SXiaoDong Huang #include <pm_pd_regs.h>
24036935a8SXiaoDong Huang #include <secure.h>
25036935a8SXiaoDong Huang #include <soc.h>
26036935a8SXiaoDong Huang 
27036935a8SXiaoDong Huang static struct psram_data_t *psram_sleep_cfg =
28036935a8SXiaoDong Huang 	(struct psram_data_t *)&sys_sleep_flag_sram;
29036935a8SXiaoDong Huang 
30036935a8SXiaoDong Huang struct rk3576_sleep_ddr_data {
31036935a8SXiaoDong Huang 	uint32_t cru_mode_con, secure_cru_mode;
32036935a8SXiaoDong Huang 	uint32_t gpio0a_iomux_l, gpio0a_iomux_h, gpio0b_iomux_l;
33036935a8SXiaoDong Huang 	uint32_t pmu2_bisr_glb_con;
34036935a8SXiaoDong Huang 	uint32_t pmu2_c0_ack_sel_con0, pmu2_c1_ack_sel_con0, pmu2_c2_ack_sel_con0;
35036935a8SXiaoDong Huang 	uint32_t pmu2_fast_pwr_con, pmu2_pwrgt_sft_con0;
36036935a8SXiaoDong Huang 	uint32_t pmu0grf_soc_con0, pmu0grf_soc_con1, pmu0grf_soc_con5;
37036935a8SXiaoDong Huang 	uint32_t pmu_pd_st, bus_idle_st;
38036935a8SXiaoDong Huang 	uint32_t sys_sgrf_soc_con0;
39036935a8SXiaoDong Huang 	uint32_t ddrgrf_cha_con2, ddrgrf_chb_con2;
40036935a8SXiaoDong Huang };
41036935a8SXiaoDong Huang 
42036935a8SXiaoDong Huang static struct rk3576_sleep_ddr_data ddr_data;
43036935a8SXiaoDong Huang 
44036935a8SXiaoDong Huang void rockchip_plat_mmu_el3(void)
45036935a8SXiaoDong Huang {
46036935a8SXiaoDong Huang #ifdef PLAT_EXTRA_LD_SCRIPT
47036935a8SXiaoDong Huang 	size_t sram_size;
48036935a8SXiaoDong Huang 
49036935a8SXiaoDong Huang 	sram_size = (char *)&__bl31_pmusram_text_end -
50036935a8SXiaoDong Huang 		    (char *)PMUSRAM_BASE;
51036935a8SXiaoDong Huang 	mmap_add_region(PMUSRAM_BASE, PMUSRAM_BASE,
52036935a8SXiaoDong Huang 			sram_size, MT_MEMORY | MT_RO | MT_SECURE);
53036935a8SXiaoDong Huang 
54036935a8SXiaoDong Huang 	sram_size = (char *)&__bl31_pmusram_data_end -
55036935a8SXiaoDong Huang 		    (char *)&__bl31_pmusram_data_start;
56036935a8SXiaoDong Huang 	mmap_add_region((unsigned long)&__bl31_pmusram_data_start,
57036935a8SXiaoDong Huang 			(unsigned long)&__bl31_pmusram_data_start,
58036935a8SXiaoDong Huang 			sram_size, MT_DEVICE | MT_RW | MT_SECURE);
59036935a8SXiaoDong Huang #endif
60036935a8SXiaoDong Huang }
61036935a8SXiaoDong Huang 
62036935a8SXiaoDong Huang static int check_cpu_wfie(uint32_t cpu)
63036935a8SXiaoDong Huang {
64036935a8SXiaoDong Huang 	uint32_t loop = 0;
65036935a8SXiaoDong Huang 
66036935a8SXiaoDong Huang 	while ((mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0) & BIT(cpu + 12)) == 0 &&
67036935a8SXiaoDong Huang 	       (mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) & BIT(cpu)) == 0 &&
68036935a8SXiaoDong Huang 	       (loop < WFEI_CHECK_LOOP)) {
69036935a8SXiaoDong Huang 		udelay(1);
70036935a8SXiaoDong Huang 		loop++;
71036935a8SXiaoDong Huang 	}
72036935a8SXiaoDong Huang 
73036935a8SXiaoDong Huang 	if (loop >= WFEI_CHECK_LOOP) {
74036935a8SXiaoDong Huang 		WARN("%s: error, cpu%d (0x%x 0x%x)!\n", __func__, cpu,
75036935a8SXiaoDong Huang 		     mmio_read_32(SYS_GRF_BASE + SYSGRF_STATUS0),
76036935a8SXiaoDong Huang 		     mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST));
77036935a8SXiaoDong Huang 		return -EINVAL;
78036935a8SXiaoDong Huang 	}
79036935a8SXiaoDong Huang 
80036935a8SXiaoDong Huang 	return 0;
81036935a8SXiaoDong Huang }
82036935a8SXiaoDong Huang 
83036935a8SXiaoDong Huang static inline uint32_t cpu_power_domain_st(uint32_t cpu)
84036935a8SXiaoDong Huang {
85036935a8SXiaoDong Huang 	return !!(mmio_read_32(PMU_BASE + PMU2_CLUSTER_PWR_ST) &
86036935a8SXiaoDong Huang 		  BIT(cpu + 16));
87036935a8SXiaoDong Huang }
88036935a8SXiaoDong Huang 
89036935a8SXiaoDong Huang static int cpu_power_domain_ctr(uint32_t cpu, uint32_t pd_state)
90036935a8SXiaoDong Huang {
91036935a8SXiaoDong Huang 	uint32_t loop = 0;
92036935a8SXiaoDong Huang 	int ret = 0;
93036935a8SXiaoDong Huang 
94036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu),
95036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(pd_state, 0x1, 0));
96036935a8SXiaoDong Huang 
97036935a8SXiaoDong Huang 	dsb();
98036935a8SXiaoDong Huang 	while ((cpu_power_domain_st(cpu) != pd_state) && (loop < PD_CTR_LOOP)) {
99036935a8SXiaoDong Huang 		udelay(1);
100036935a8SXiaoDong Huang 		loop++;
101036935a8SXiaoDong Huang 	}
102036935a8SXiaoDong Huang 
103036935a8SXiaoDong Huang 	if (cpu_power_domain_st(cpu) != pd_state) {
104036935a8SXiaoDong Huang 		WARN("%s: %d, %d, error!\n", __func__, cpu, pd_state);
105036935a8SXiaoDong Huang 		ret = -EINVAL;
106036935a8SXiaoDong Huang 	}
107036935a8SXiaoDong Huang 
108036935a8SXiaoDong Huang 	return ret;
109036935a8SXiaoDong Huang }
110036935a8SXiaoDong Huang 
111036935a8SXiaoDong Huang static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
112036935a8SXiaoDong Huang {
113036935a8SXiaoDong Huang 	uint32_t val;
114036935a8SXiaoDong Huang 
115036935a8SXiaoDong Huang 	if ((mmio_read_32(PMU_BASE + PMU2_CPU_PWR_SFTCON(cpu_id)) & BIT(0)) != 0)
116036935a8SXiaoDong Huang 		return core_pwr_pd;
117036935a8SXiaoDong Huang 
118036935a8SXiaoDong Huang 	val = mmio_read_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id));
119036935a8SXiaoDong Huang 	if ((val & BIT(pmu_cpu_pm_en)) != 0) {
120036935a8SXiaoDong Huang 		if ((val & BIT(core_pwr_wfi_int)) != 0)
121036935a8SXiaoDong Huang 			return core_pwr_wfi_int;
122036935a8SXiaoDong Huang 		else if ((val & BIT(pmu_cpu_pm_sft_wakeup_en)) != 0)
123036935a8SXiaoDong Huang 			return core_pwr_wfi_reset;
124036935a8SXiaoDong Huang 		else
125036935a8SXiaoDong Huang 			return core_pwr_wfi;
126036935a8SXiaoDong Huang 	} else {
127036935a8SXiaoDong Huang 		return -1;
128036935a8SXiaoDong Huang 	}
129036935a8SXiaoDong Huang }
130036935a8SXiaoDong Huang 
131036935a8SXiaoDong Huang static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
132036935a8SXiaoDong Huang {
133036935a8SXiaoDong Huang }
134036935a8SXiaoDong Huang 
135036935a8SXiaoDong Huang static int cpus_power_domain_on(uint32_t cpu_id)
136036935a8SXiaoDong Huang {
137036935a8SXiaoDong Huang 	uint32_t cfg_info;
138036935a8SXiaoDong Huang 	/*
139036935a8SXiaoDong Huang 	 * There are two ways to powering on or off on core.
140036935a8SXiaoDong Huang 	 * 1) Control it power domain into on or off in PMU_PWRDN_CON reg
141036935a8SXiaoDong Huang 	 * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
142036935a8SXiaoDong Huang 	 *	then, if the core enter into wfi, it power domain will be
143036935a8SXiaoDong Huang 	 *	powered off automatically.
144036935a8SXiaoDong Huang 	 */
145036935a8SXiaoDong Huang 
146036935a8SXiaoDong Huang 	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
147036935a8SXiaoDong Huang 
148036935a8SXiaoDong Huang 	if (cfg_info == core_pwr_pd) {
149036935a8SXiaoDong Huang 		/* disable core_pm cfg */
150036935a8SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
151036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(0, 0xf, 0));
152036935a8SXiaoDong Huang 		/* if the cores have be on, power off it firstly */
153036935a8SXiaoDong Huang 		if (cpu_power_domain_st(cpu_id) == pmu_pd_on)
154036935a8SXiaoDong Huang 			cpu_power_domain_ctr(cpu_id, pmu_pd_off);
155036935a8SXiaoDong Huang 
156036935a8SXiaoDong Huang 		cpu_power_domain_ctr(cpu_id, pmu_pd_on);
157036935a8SXiaoDong Huang 	} else {
158036935a8SXiaoDong Huang 		if (cpu_power_domain_st(cpu_id) == pmu_pd_on) {
159036935a8SXiaoDong Huang 			WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id);
160036935a8SXiaoDong Huang 			return -EINVAL;
161036935a8SXiaoDong Huang 		}
162036935a8SXiaoDong Huang 
163036935a8SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
164036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(1, 0x1, pmu_cpu_pm_sft_wakeup_en));
165036935a8SXiaoDong Huang 		dsb();
166036935a8SXiaoDong Huang 	}
167036935a8SXiaoDong Huang 
168036935a8SXiaoDong Huang 	return 0;
169036935a8SXiaoDong Huang }
170036935a8SXiaoDong Huang 
171036935a8SXiaoDong Huang static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
172036935a8SXiaoDong Huang {
173036935a8SXiaoDong Huang 	uint32_t core_pm_value;
174036935a8SXiaoDong Huang 
175036935a8SXiaoDong Huang 	if (cpu_power_domain_st(cpu_id) == pmu_pd_off)
176036935a8SXiaoDong Huang 		return 0;
177036935a8SXiaoDong Huang 
178036935a8SXiaoDong Huang 	if (pd_cfg == core_pwr_pd) {
179036935a8SXiaoDong Huang 		if (check_cpu_wfie(cpu_id))
180036935a8SXiaoDong Huang 			return -EINVAL;
181036935a8SXiaoDong Huang 
182036935a8SXiaoDong Huang 		/* disable core_pm cfg */
183036935a8SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
184036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(0, 0xf, 0));
185036935a8SXiaoDong Huang 
186036935a8SXiaoDong Huang 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
187036935a8SXiaoDong Huang 		cpu_power_domain_ctr(cpu_id, pmu_pd_off);
188036935a8SXiaoDong Huang 	} else {
189036935a8SXiaoDong Huang 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
190036935a8SXiaoDong Huang 
191036935a8SXiaoDong Huang 		core_pm_value = BIT(pmu_cpu_pm_en) | BIT(pmu_cpu_pm_dis_int);
192036935a8SXiaoDong Huang 		if (pd_cfg == core_pwr_wfi_int)
193036935a8SXiaoDong Huang 			core_pm_value |= BIT(pmu_cpu_pm_int_wakeup_en);
194036935a8SXiaoDong Huang 		else if (pd_cfg == core_pwr_wfi_reset)
195036935a8SXiaoDong Huang 			core_pm_value |= BIT(pmu_cpu_pm_sft_wakeup_en);
196036935a8SXiaoDong Huang 
197036935a8SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
198036935a8SXiaoDong Huang 			      BITS_WITH_WMASK(core_pm_value, 0xf, 0));
199036935a8SXiaoDong Huang 		dsb();
200036935a8SXiaoDong Huang 	}
201036935a8SXiaoDong Huang 
202036935a8SXiaoDong Huang 	return 0;
203036935a8SXiaoDong Huang }
204036935a8SXiaoDong Huang 
205036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
206036935a8SXiaoDong Huang {
207036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
208036935a8SXiaoDong Huang 
209036935a8SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
210036935a8SXiaoDong Huang 	assert(cpuson_flags[cpu_id] == 0);
211036935a8SXiaoDong Huang 	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
212036935a8SXiaoDong Huang 	cpuson_entry_point[cpu_id] = entrypoint;
213036935a8SXiaoDong Huang 	dsb();
214036935a8SXiaoDong Huang 
215036935a8SXiaoDong Huang 	cpus_power_domain_on(cpu_id);
216036935a8SXiaoDong Huang 
217036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
218036935a8SXiaoDong Huang }
219036935a8SXiaoDong Huang 
220036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_off(void)
221036935a8SXiaoDong Huang {
222036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
223036935a8SXiaoDong Huang 
224036935a8SXiaoDong Huang 	cpus_power_domain_off(cpu_id, core_pwr_wfi);
225036935a8SXiaoDong Huang 
226036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
227036935a8SXiaoDong Huang }
228036935a8SXiaoDong Huang 
229036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on_finish(void)
230036935a8SXiaoDong Huang {
231036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
232036935a8SXiaoDong Huang 
233036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
234036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 0));
235036935a8SXiaoDong Huang 
236036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
237036935a8SXiaoDong Huang }
238036935a8SXiaoDong Huang 
239036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_suspend(void)
240036935a8SXiaoDong Huang {
241036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
242036935a8SXiaoDong Huang 
243036935a8SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
244036935a8SXiaoDong Huang 	assert(cpuson_flags[cpu_id] == 0);
245036935a8SXiaoDong Huang 	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
246036935a8SXiaoDong Huang 	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
247036935a8SXiaoDong Huang 	dsb();
248036935a8SXiaoDong Huang 
249036935a8SXiaoDong Huang 	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
250036935a8SXiaoDong Huang 
251036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
252036935a8SXiaoDong Huang }
253036935a8SXiaoDong Huang 
254036935a8SXiaoDong Huang int rockchip_soc_cores_pwr_dm_resume(void)
255036935a8SXiaoDong Huang {
256036935a8SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
257036935a8SXiaoDong Huang 
258036935a8SXiaoDong Huang 	/* Disable core_pm */
259036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
260036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 0));
261036935a8SXiaoDong Huang 
262036935a8SXiaoDong Huang 	return PSCI_E_SUCCESS;
263036935a8SXiaoDong Huang }
264036935a8SXiaoDong Huang 
265036935a8SXiaoDong Huang void nonboot_cpus_off(void)
266036935a8SXiaoDong Huang {
267036935a8SXiaoDong Huang 	uint32_t boot_cpu, cpu;
268036935a8SXiaoDong Huang 
269036935a8SXiaoDong Huang 	boot_cpu = plat_my_core_pos();
270036935a8SXiaoDong Huang 
271036935a8SXiaoDong Huang 	/* turn off noboot cpus */
272036935a8SXiaoDong Huang 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
273036935a8SXiaoDong Huang 		if (cpu == boot_cpu)
274036935a8SXiaoDong Huang 			continue;
275036935a8SXiaoDong Huang 
276036935a8SXiaoDong Huang 		cpus_power_domain_off(cpu, core_pwr_pd);
277036935a8SXiaoDong Huang 	}
278036935a8SXiaoDong Huang }
279036935a8SXiaoDong Huang 
280036935a8SXiaoDong Huang static __pmusramfunc void ddr_resume(void)
281036935a8SXiaoDong Huang {
282036935a8SXiaoDong Huang 	uint32_t key_upd_msk =
283036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pmu_pd_vop) ? 0x3 : 0x7;
284036935a8SXiaoDong Huang 
285036935a8SXiaoDong Huang 	/* hptimer is 24M here */
286036935a8SXiaoDong Huang 	write_cntfrq_el0(24000000);
287036935a8SXiaoDong Huang 
288036935a8SXiaoDong Huang 	/* release cpu1~cpu7 to make pmu1_fsm exit */
289036935a8SXiaoDong Huang 	mmio_write_32(CCI_GRF_BASE + CCIGRF_CON(4), 0xffffffff);
290036935a8SXiaoDong Huang 	mmio_write_32(LITCORE_GRF_BASE + COREGRF_CPU_CON(1),
291036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x77, 0xff, 4));
292036935a8SXiaoDong Huang 
293036935a8SXiaoDong Huang 	/* wait pmu1 fsm over */
294036935a8SXiaoDong Huang 	while ((mmio_read_32(PMU_BASE + PMU1_PWR_FSM) & 0xf) != 0)
295036935a8SXiaoDong Huang 		;
296036935a8SXiaoDong Huang 
297036935a8SXiaoDong Huang 	/* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */
298036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000);
299036935a8SXiaoDong Huang 	dsb();
300036935a8SXiaoDong Huang 
301036935a8SXiaoDong Huang 	/* SOC_CON19.vop/center/cci_ddr_hash_key_update_en */
302036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00070000 | key_upd_msk);
303036935a8SXiaoDong Huang 
304036935a8SXiaoDong Huang 	/* SOC_STATUS.center/cci_ddr_hash_key_shift_ready */
305036935a8SXiaoDong Huang 	while (((mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_STATUS) >> 12) & key_upd_msk) != key_upd_msk)
306036935a8SXiaoDong Huang 		;
307036935a8SXiaoDong Huang 
308036935a8SXiaoDong Huang 	/* CCI_BASE.ctrl_override_reg Attr:W1C addrmap strobe */
309036935a8SXiaoDong Huang 	mmio_setbits_32(CCI_BASE + 0x0, 0x1 << 29);
310036935a8SXiaoDong Huang 
311036935a8SXiaoDong Huang 	/* SOC_CON19.vop/center/cci_ddr_hash_key_auto_update_en */
312036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19), 0x00700070);
313036935a8SXiaoDong Huang }
314036935a8SXiaoDong Huang 
315036935a8SXiaoDong Huang static uint32_t clk_save[CRU_CLKGATE_CON_CNT + PHP_CRU_CLKGATE_CON_CNT +
316036935a8SXiaoDong Huang 			 SECURE_CRU_CLKGATE_CON_CNT + SECURE_SCRU_CLKGATE_CON_CNT +
317036935a8SXiaoDong Huang 			 PMU1CRU_CLKGATE_CON_CNT + PMU1SCRU_CLKGATE_CON_CNT];
318036935a8SXiaoDong Huang 
319036935a8SXiaoDong Huang void clk_gate_con_disable(void)
320036935a8SXiaoDong Huang {
321036935a8SXiaoDong Huang 	int i;
322036935a8SXiaoDong Huang 
323036935a8SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++) {
324036935a8SXiaoDong Huang 		/* Don't open wdt0 clk (cru_gate16[7:8] */
325036935a8SXiaoDong Huang 		if (i == 16) {
326036935a8SXiaoDong Huang 			mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
327036935a8SXiaoDong Huang 				      0xfe7f0000);
328036935a8SXiaoDong Huang 		} else {
329036935a8SXiaoDong Huang 			mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
330036935a8SXiaoDong Huang 				      0xffff0000);
331036935a8SXiaoDong Huang 		}
332036935a8SXiaoDong Huang 	}
333036935a8SXiaoDong Huang 
334036935a8SXiaoDong Huang 	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++)
335036935a8SXiaoDong Huang 		mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i), 0xffff0000);
336036935a8SXiaoDong Huang 
337036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++)
338036935a8SXiaoDong Huang 		mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i), 0xffff0000);
339036935a8SXiaoDong Huang 
340036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++)
341036935a8SXiaoDong Huang 		mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i), 0xffff0000);
342036935a8SXiaoDong Huang 
343036935a8SXiaoDong Huang 	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++)
344036935a8SXiaoDong Huang 		mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i), 0xffff0000);
345036935a8SXiaoDong Huang 
346036935a8SXiaoDong Huang 	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++)
347036935a8SXiaoDong Huang 		mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i), 0xffff0000);
348036935a8SXiaoDong Huang }
349036935a8SXiaoDong Huang 
350036935a8SXiaoDong Huang void clk_gate_con_save(void)
351036935a8SXiaoDong Huang {
352036935a8SXiaoDong Huang 	int i, j = 0;
353036935a8SXiaoDong Huang 
354036935a8SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++)
355036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i));
356036935a8SXiaoDong Huang 
357036935a8SXiaoDong Huang 	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++)
358036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i));
359036935a8SXiaoDong Huang 
360036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++)
361036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i));
362036935a8SXiaoDong Huang 
363036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++)
364036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i));
365036935a8SXiaoDong Huang 
366036935a8SXiaoDong Huang 	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++)
367036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i));
368036935a8SXiaoDong Huang 
369036935a8SXiaoDong Huang 	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++)
370036935a8SXiaoDong Huang 		clk_save[j] = mmio_read_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i));
371036935a8SXiaoDong Huang }
372036935a8SXiaoDong Huang 
373036935a8SXiaoDong Huang void clk_gate_con_restore(void)
374036935a8SXiaoDong Huang {
375036935a8SXiaoDong Huang 	int i, j = 0;
376036935a8SXiaoDong Huang 
377036935a8SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++)
378036935a8SXiaoDong Huang 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
379036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
380036935a8SXiaoDong Huang 
381036935a8SXiaoDong Huang 	for (i = 0; i < PHP_CRU_CLKGATE_CON_CNT; i++, j++)
382036935a8SXiaoDong Huang 		mmio_write_32(PHP_CRU_BASE + PHP_CRU_CLKGATE_CON(i),
383036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
384036935a8SXiaoDong Huang 
385036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_CRU_CLKGATE_CON_CNT; i++, j++)
386036935a8SXiaoDong Huang 		mmio_write_32(SECURE_CRU_BASE + SECURE_CRU_CLKGATE_CON(i),
387036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
388036935a8SXiaoDong Huang 
389036935a8SXiaoDong Huang 	for (i = 0; i < SECURE_SCRU_CLKGATE_CON_CNT; i++, j++)
390036935a8SXiaoDong Huang 		mmio_write_32(SECURE_CRU_BASE + SECURE_SCRU_CLKGATE_CON(i),
391036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
392036935a8SXiaoDong Huang 
393036935a8SXiaoDong Huang 	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++)
394036935a8SXiaoDong Huang 		mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKGATE_CON(i),
395036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
396036935a8SXiaoDong Huang 
397036935a8SXiaoDong Huang 	for (i = 0; i < PMU1SCRU_CLKGATE_CON_CNT; i++, j++)
398036935a8SXiaoDong Huang 		mmio_write_32(PMU1_CRU_BASE + PMU1SCRU_CLKGATE_CON(i),
399036935a8SXiaoDong Huang 			      WITH_16BITS_WMSK(clk_save[j]));
400036935a8SXiaoDong Huang }
401036935a8SXiaoDong Huang 
402036935a8SXiaoDong Huang void pmu_bus_idle_req(uint32_t bus, uint32_t state)
403036935a8SXiaoDong Huang {
404036935a8SXiaoDong Huang 	uint32_t wait_cnt = 0;
405036935a8SXiaoDong Huang 
406036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_SFTCON(bus / 16),
407036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(state, 0x1, bus % 16));
408036935a8SXiaoDong Huang 
409036935a8SXiaoDong Huang 	while (pmu_bus_idle_st(bus) != state ||
410036935a8SXiaoDong Huang 	       pmu_bus_idle_ack(bus) != state) {
411036935a8SXiaoDong Huang 		if (++wait_cnt > BUS_IDLE_LOOP)
412036935a8SXiaoDong Huang 			break;
413036935a8SXiaoDong Huang 		udelay(1);
414036935a8SXiaoDong Huang 	}
415036935a8SXiaoDong Huang 
416036935a8SXiaoDong Huang 	if (wait_cnt > BUS_IDLE_LOOP)
417036935a8SXiaoDong Huang 		WARN("%s: can't  wait state %d for bus %d (0x%x)\n",
418036935a8SXiaoDong Huang 		     __func__, state, bus,
419036935a8SXiaoDong Huang 		     mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST));
420036935a8SXiaoDong Huang }
421036935a8SXiaoDong Huang 
422036935a8SXiaoDong Huang static inline uint32_t pmu_power_domain_st(uint32_t pd)
423036935a8SXiaoDong Huang {
424036935a8SXiaoDong Huang 	return mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST) & BIT(pd) ?
425036935a8SXiaoDong Huang 	       pmu_pd_off :
426036935a8SXiaoDong Huang 	       pmu_pd_on;
427036935a8SXiaoDong Huang }
428036935a8SXiaoDong Huang 
429036935a8SXiaoDong Huang int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
430036935a8SXiaoDong Huang {
431036935a8SXiaoDong Huang 	uint32_t loop = 0;
432036935a8SXiaoDong Huang 	int ret = 0;
433036935a8SXiaoDong Huang 
434036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(pd / 16),
435036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(pd_state, 0x1, pd % 16));
436036935a8SXiaoDong Huang 	dsb();
437036935a8SXiaoDong Huang 
438036935a8SXiaoDong Huang 	while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
439036935a8SXiaoDong Huang 		udelay(1);
440036935a8SXiaoDong Huang 		loop++;
441036935a8SXiaoDong Huang 	}
442036935a8SXiaoDong Huang 
443036935a8SXiaoDong Huang 	if (pmu_power_domain_st(pd) != pd_state) {
444036935a8SXiaoDong Huang 		WARN("%s: %d, %d, (0x%x) error!\n", __func__, pd, pd_state,
445036935a8SXiaoDong Huang 		     mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST));
446036935a8SXiaoDong Huang 		ret = -EINVAL;
447036935a8SXiaoDong Huang 	}
448036935a8SXiaoDong Huang 
449036935a8SXiaoDong Huang 	return ret;
450036935a8SXiaoDong Huang }
451036935a8SXiaoDong Huang 
452036935a8SXiaoDong Huang static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
453036935a8SXiaoDong Huang {
454036935a8SXiaoDong Huang 	uint32_t state;
455036935a8SXiaoDong Huang 
456036935a8SXiaoDong Huang 	if (pmu_power_domain_st(pd_id) == pd_state)
457036935a8SXiaoDong Huang 		goto out;
458036935a8SXiaoDong Huang 
459036935a8SXiaoDong Huang 	if (pd_state == pmu_pd_on)
460036935a8SXiaoDong Huang 		pmu_power_domain_ctr(pd_id, pd_state);
461036935a8SXiaoDong Huang 
462036935a8SXiaoDong Huang 	state = (pd_state == pmu_pd_off) ? pmu_bus_idle : pmu_bus_active;
463036935a8SXiaoDong Huang 
464036935a8SXiaoDong Huang 	switch (pd_id) {
465036935a8SXiaoDong Huang 	case pmu_pd_npu:
466036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_npusys, state);
467036935a8SXiaoDong Huang 		break;
468036935a8SXiaoDong Huang 	case pmu_pd_secure:
469036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_secure, state);
470036935a8SXiaoDong Huang 		break;
471036935a8SXiaoDong Huang 	case pmu_pd_nvm:
472036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_nvm, state);
473036935a8SXiaoDong Huang 		break;
474036935a8SXiaoDong Huang 	case pmu_pd_sd_gmac:
475036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_gmac, state);
476036935a8SXiaoDong Huang 		break;
477036935a8SXiaoDong Huang 	case pmu_pd_audio:
478036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_audio, state);
479036935a8SXiaoDong Huang 		break;
480036935a8SXiaoDong Huang 	case pmu_pd_php:
481036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_php, state);
482036935a8SXiaoDong Huang 		break;
483036935a8SXiaoDong Huang 	case pmu_pd_subphp:
484036935a8SXiaoDong Huang 		break;
485036935a8SXiaoDong Huang 	case pmu_pd_vop:
486036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vop, state);
487036935a8SXiaoDong Huang 		break;
488036935a8SXiaoDong Huang 	case pmu_pd_vop_smart:
489036935a8SXiaoDong Huang 		break;
490036935a8SXiaoDong Huang 	case pmu_pd_vop_clst:
491036935a8SXiaoDong Huang 		break;
492036935a8SXiaoDong Huang 	case pmu_pd_vo1:
493036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vo1, state);
494036935a8SXiaoDong Huang 		break;
495036935a8SXiaoDong Huang 	case pmu_pd_vo0:
496036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vo0, state);
497036935a8SXiaoDong Huang 		break;
498036935a8SXiaoDong Huang 	case pmu_pd_usb:
499036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_usb, state);
500036935a8SXiaoDong Huang 		break;
501036935a8SXiaoDong Huang 	case pmu_pd_vi:
502036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vi, state);
503036935a8SXiaoDong Huang 		break;
504036935a8SXiaoDong Huang 	case pmu_pd_vepu0:
505036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vepu0, state);
506036935a8SXiaoDong Huang 		break;
507036935a8SXiaoDong Huang 	case pmu_pd_vepu1:
508036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vepu1, state);
509036935a8SXiaoDong Huang 		break;
510036935a8SXiaoDong Huang 	case pmu_pd_vdec:
511036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vdec, state);
512036935a8SXiaoDong Huang 		break;
513036935a8SXiaoDong Huang 	case pmu_pd_vpu:
514036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_vpu, state);
515036935a8SXiaoDong Huang 		break;
516036935a8SXiaoDong Huang 	case pmu_pd_nputop:
517036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_nputop, state);
518036935a8SXiaoDong Huang 		break;
519036935a8SXiaoDong Huang 	case pmu_pd_npu0:
520036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_npu0, state);
521036935a8SXiaoDong Huang 		break;
522036935a8SXiaoDong Huang 	case pmu_pd_npu1:
523036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_npu1, state);
524036935a8SXiaoDong Huang 		break;
525036935a8SXiaoDong Huang 	case pmu_pd_gpu:
526036935a8SXiaoDong Huang 		pmu_bus_idle_req(pmu_bus_id_gpu, state);
527036935a8SXiaoDong Huang 		break;
528036935a8SXiaoDong Huang 	default:
529036935a8SXiaoDong Huang 		break;
530036935a8SXiaoDong Huang 	}
531036935a8SXiaoDong Huang 
532036935a8SXiaoDong Huang 	if (pd_state == pmu_pd_off)
533036935a8SXiaoDong Huang 		pmu_power_domain_ctr(pd_id, pd_state);
534036935a8SXiaoDong Huang 
535036935a8SXiaoDong Huang out:
536036935a8SXiaoDong Huang 	return 0;
537036935a8SXiaoDong Huang }
538036935a8SXiaoDong Huang 
539036935a8SXiaoDong Huang static void pmu_power_domains_suspend(void)
540036935a8SXiaoDong Huang {
541036935a8SXiaoDong Huang 	ddr_data.pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST);
542036935a8SXiaoDong Huang 	ddr_data.bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST);
543036935a8SXiaoDong Huang 	ddr_data.pmu2_pwrgt_sft_con0 = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0));
544036935a8SXiaoDong Huang 
545036935a8SXiaoDong Huang 	qos_save();
546036935a8SXiaoDong Huang 
547036935a8SXiaoDong Huang 	pd_usb2phy_save();
548036935a8SXiaoDong Huang 
549036935a8SXiaoDong Huang 	if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0)
550036935a8SXiaoDong Huang 		pd_php_save();
551036935a8SXiaoDong Huang }
552036935a8SXiaoDong Huang 
553036935a8SXiaoDong Huang static void pmu_power_domains_resume(void)
554036935a8SXiaoDong Huang {
555036935a8SXiaoDong Huang 	int i;
556036935a8SXiaoDong Huang 
557036935a8SXiaoDong Huang 	for (i = 0; i < pmu_pd_id_max; i++) {
558036935a8SXiaoDong Huang 		/* vop smart/clst pd is not controlled by pmu */
559036935a8SXiaoDong Huang 		if (i == pmu_pd_vop_smart || i == pmu_pd_vop_clst)
560036935a8SXiaoDong Huang 			continue;
561036935a8SXiaoDong Huang 
562036935a8SXiaoDong Huang 		pmu_set_power_domain(i, !!(ddr_data.pmu_pd_st & BIT(i)));
563036935a8SXiaoDong Huang 	}
564036935a8SXiaoDong Huang 
565036935a8SXiaoDong Huang 	/* restore vop smart/clst pd of pmu2_pwrgt_sft_con0 */
566036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(0),
567036935a8SXiaoDong Huang 		      0x30000000 | ddr_data.pmu2_pwrgt_sft_con0);
568036935a8SXiaoDong Huang 
569036935a8SXiaoDong Huang 	for (i = pmu_bus_id_max - 1; i >= 0; i--)
570036935a8SXiaoDong Huang 		pmu_bus_idle_req(i, !!(ddr_data.bus_idle_st & BIT(i)));
571036935a8SXiaoDong Huang 
572036935a8SXiaoDong Huang 	if ((ddr_data.pmu_pd_st & BIT(pmu_pd_php)) == 0)
573036935a8SXiaoDong Huang 		pd_php_restore();
574036935a8SXiaoDong Huang 
575036935a8SXiaoDong Huang 	pd_usb2phy_restore();
576036935a8SXiaoDong Huang 
577036935a8SXiaoDong Huang 	qos_restore();
578036935a8SXiaoDong Huang }
579036935a8SXiaoDong Huang 
580036935a8SXiaoDong Huang static void ddr_sleep_config(void)
581036935a8SXiaoDong Huang {
582036935a8SXiaoDong Huang 	ddr_data.ddrgrf_cha_con2 =
583036935a8SXiaoDong Huang 		mmio_read_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2));
584036935a8SXiaoDong Huang 	ddr_data.ddrgrf_chb_con2 =
585036935a8SXiaoDong Huang 		mmio_read_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2));
586036935a8SXiaoDong Huang 
587036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2), 0x0a000a00);
588036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2), 0x0a000a00);
589036935a8SXiaoDong Huang }
590036935a8SXiaoDong Huang 
591036935a8SXiaoDong Huang static void ddr_sleep_config_restore(void)
592036935a8SXiaoDong Huang {
593036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHA_CON(2),
594036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.ddrgrf_cha_con2));
595036935a8SXiaoDong Huang 	mmio_write_32(DDR_GRF_BASE + DDRGRF_CHB_CON(2),
596036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.ddrgrf_chb_con2));
597036935a8SXiaoDong Huang }
598036935a8SXiaoDong Huang 
599036935a8SXiaoDong Huang static void sleep_pin_config(void)
600036935a8SXiaoDong Huang {
601036935a8SXiaoDong Huang 	/* pwr0 sleep: gpio0_a3 */
602036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1),
603036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x7, 0xf, 0));
604036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0),
605036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0x1, 7));
606036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
607036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(9, 0xfu, 12));
608036935a8SXiaoDong Huang }
609036935a8SXiaoDong Huang 
610036935a8SXiaoDong Huang static void pmu_sleep_config(void)
611036935a8SXiaoDong Huang {
612036935a8SXiaoDong Huang 	uint32_t pmu1_wkup_int_con;
613036935a8SXiaoDong Huang 	uint32_t pmu1_pwr_con, pmu1_ddr_pwr_con, pmu1cru_pwr_con, pmu1_pll_pd_con;
614036935a8SXiaoDong Huang 	uint32_t pmu2_bus_idle_con[2], pmu2_pwr_gt_con[2];
615036935a8SXiaoDong Huang 	uint32_t key_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_vop) ? 0x3 : 0x7;
616036935a8SXiaoDong Huang 	uint32_t fw_lkp_upd_msk = ddr_data.pmu_pd_st & BIT(pmu_pd_npu) ? 0x3 : 0x7;
617036935a8SXiaoDong Huang 	uint32_t fw_ddr_upd_msk = key_upd_msk;
618036935a8SXiaoDong Huang 	uint32_t pmu_pd_st = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST);
619036935a8SXiaoDong Huang 	uint32_t bus_idle_st = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST);
620036935a8SXiaoDong Huang 
621036935a8SXiaoDong Huang 	ddr_data.pmu2_bisr_glb_con = mmio_read_32(PMU_BASE + PMU2_BISR_GLB_CON);
622036935a8SXiaoDong Huang 
623036935a8SXiaoDong Huang 	ddr_data.pmu2_fast_pwr_con =
624036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_FAST_POWER_CON);
625036935a8SXiaoDong Huang 
626036935a8SXiaoDong Huang 	ddr_data.pmu2_c0_ack_sel_con0 =
627036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0));
628036935a8SXiaoDong Huang 	ddr_data.pmu2_c1_ack_sel_con0 =
629036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0));
630036935a8SXiaoDong Huang 	ddr_data.pmu2_c2_ack_sel_con0 =
631036935a8SXiaoDong Huang 		mmio_read_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0));
632036935a8SXiaoDong Huang 	ddr_data.pmu0grf_soc_con5 =
633036935a8SXiaoDong Huang 		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5));
634036935a8SXiaoDong Huang 
635036935a8SXiaoDong Huang 	/* set tsadc_shut_m0 pin iomux to gpio */
636036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
637036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 4));
638036935a8SXiaoDong Huang 
639036935a8SXiaoDong Huang 	pmu1_wkup_int_con =
640036935a8SXiaoDong Huang 		BIT(pmu_wkup_cpu0_int) |
641036935a8SXiaoDong Huang 		BIT(pmu_wkup_gpio0_int);
642036935a8SXiaoDong Huang 
643036935a8SXiaoDong Huang 	pmu1_pwr_con =
644036935a8SXiaoDong Huang 		BIT(pmu_powermode_en) |
645036935a8SXiaoDong Huang 		/* BIT(pmu_scu0_byp) | */
646036935a8SXiaoDong Huang 		/* BIT(pmu_scu1_byp) | */
647036935a8SXiaoDong Huang 		/* BIT(pmu_cci_byp) | */
648036935a8SXiaoDong Huang 		/* BIT(pmu_bus_byp) | */
649036935a8SXiaoDong Huang 		/* BIT(pmu_ddr_byp) | */
650036935a8SXiaoDong Huang 		/* BIT(pmu_pwrgt_byp) | */
651036935a8SXiaoDong Huang 		/* BIT(pmu_cru_byp) | */
652036935a8SXiaoDong Huang 		BIT(pmu_qch_byp) |
653036935a8SXiaoDong Huang 		/* BIT(pmu_wfi_byp) | */
654036935a8SXiaoDong Huang 		BIT(pmu_slp_cnt_en);
655036935a8SXiaoDong Huang 
656036935a8SXiaoDong Huang 	pmu1_ddr_pwr_con = 0;
657036935a8SXiaoDong Huang 
658036935a8SXiaoDong Huang 	pmu1_pll_pd_con =
659036935a8SXiaoDong Huang 		BIT(pmu_bpll_pd_en) |
660036935a8SXiaoDong Huang 		BIT(pmu_lpll_pd_en) |
661036935a8SXiaoDong Huang 		BIT(pmu_spll_pd_en) |
662036935a8SXiaoDong Huang 		BIT(pmu_gpll_pd_en) |
663036935a8SXiaoDong Huang 		BIT(pmu_cpll_pd_en) |
664036935a8SXiaoDong Huang 		BIT(pmu_ppll_pd_en) |
665036935a8SXiaoDong Huang 		BIT(pmu_aupll_pd_en) |
666036935a8SXiaoDong Huang 		BIT(pmu_vpll_pd_en);
667036935a8SXiaoDong Huang 
668036935a8SXiaoDong Huang 	pmu1cru_pwr_con =
669036935a8SXiaoDong Huang 		BIT(pmu_alive_osc_mode_en) |
670036935a8SXiaoDong Huang 		BIT(pmu_io_sleep_en) |
671036935a8SXiaoDong Huang 		BIT(pmu_power_off_en);
672036935a8SXiaoDong Huang 
673036935a8SXiaoDong Huang 	pmu2_bus_idle_con[0] = 0xffff & ~(bus_idle_st & 0xffff);
674036935a8SXiaoDong Huang 	pmu2_bus_idle_con[1] = 0x3fff & ~(bus_idle_st >> 16);
675036935a8SXiaoDong Huang 
676036935a8SXiaoDong Huang 	pmu2_pwr_gt_con[0] = 0xffff & ~(pmu_pd_st & 0xffff);
677036935a8SXiaoDong Huang 	pmu2_pwr_gt_con[1] = 0x03ff & ~(pmu_pd_st >> 16);
678036935a8SXiaoDong Huang 
679036935a8SXiaoDong Huang 	pmu2_pwr_gt_con[0] &=
680036935a8SXiaoDong Huang 		~(BIT(pmu_pd_secure) |
681036935a8SXiaoDong Huang 		  BIT(pmu_pd_bus) |
682036935a8SXiaoDong Huang 		  BIT(pmu_pd_center) |
683036935a8SXiaoDong Huang 		  BIT(pmu_pd_ddr));
684036935a8SXiaoDong Huang 
685036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0x00030003);
686036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON0, 0x03ff0000);
687036935a8SXiaoDong Huang 
688036935a8SXiaoDong Huang 	/* disable repair */
689036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON, 0x00010000);
690036935a8SXiaoDong Huang 
691036935a8SXiaoDong Huang 	/* disable ddr_hash_key update.
692036935a8SXiaoDong Huang 	 * enable disable ddr_hash_key auto update.
693036935a8SXiaoDong Huang 	 * wait ddr_hash_key auto update.
694036935a8SXiaoDong Huang 	 */
695036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(19),
696036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(key_upd_msk, 0x7, 8));
697036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1,
698036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(fw_lkp_upd_msk, 0x7, 10));
699036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_FW_BASE + FW_SGRF_KEYUPD_CON1,
700036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(fw_ddr_upd_msk, 0x7u, 13));
701036935a8SXiaoDong Huang 
702036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_PMIC_STABLE_CNT_THRES, 24000 * 5);
703036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_OSC_STABLE_CNT_THRES, 24000 * 5);
704036935a8SXiaoDong Huang 
705036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_OSC_STABLE_CNT_THRESH, 24000 * 5);
706036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_STABLE_CNT_THRESH, 24000 * 5);
707036935a8SXiaoDong Huang 
708036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_SLEEP_CNT_THRESH, 24000 * 15);
709036935a8SXiaoDong Huang 
710036935a8SXiaoDong Huang 	/* Pmu's clk has switched to 24M back When pmu FSM counts
711036935a8SXiaoDong Huang 	 * the follow counters, so we should use 24M to calculate
712036935a8SXiaoDong Huang 	 * these counters.
713036935a8SXiaoDong Huang 	 */
714036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_WAKEUP_RST_CLR_CNT_THRES, 12000);
715036935a8SXiaoDong Huang 
716036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_WAKEUP_RST_CLR_CNT_THRESH, 12000);
717036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PLL_LOCK_CNT_THRESH, 12000);
718036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PWM_SWITCH_CNT_THRESH,
719036935a8SXiaoDong Huang 		      24000 * 2);
720036935a8SXiaoDong Huang 
721036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_PWRUP_CNT_THRESH, 0);
722036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_PWRDN_CNT_THRESH, 0);
723036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_STABLE_CNT_THRESH, 0);
724036935a8SXiaoDong Huang 
725036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_0, 0);
726036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_0, 0);
727036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_1, 0);
728036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_1, 0);
729036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRUP_CNT_THRESH_2, 0);
730036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_PWRDN_CNT_THRESH_2, 0);
731036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON, 0xffff0007);
732036935a8SXiaoDong Huang 
733036935a8SXiaoDong Huang 	/* pmu_clst_idle_con */
734036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0007);
735036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CLUSTER1_IDLE_CON, 0xffff0007);
736036935a8SXiaoDong Huang 
737036935a8SXiaoDong Huang 	/* pmu_scu_pwr_con */
738036935a8SXiaoDong Huang 	/* L2's flush and idle by hardware, so need to enable wfil2 bypass */
739036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff020f);
740036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU1_PWR_CON, 0xffff020f);
741036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_AUTO_PWR_CON, 0x00070000);
742036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU1_AUTO_PWR_CON, 0x00070000);
743036935a8SXiaoDong Huang 
744036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0009);
745036935a8SXiaoDong Huang 
746036935a8SXiaoDong Huang 	/* pmu_int_msk_con */
747036935a8SXiaoDong Huang 	/* mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, BITS_WITH_WMASK(1, 0x1, 0)); */
748036935a8SXiaoDong Huang 
749036935a8SXiaoDong Huang 	/* pmu_pwr_con */
750036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PWR_CON, WITH_16BITS_WMSK(pmu1_pwr_con));
751036935a8SXiaoDong Huang 
752036935a8SXiaoDong Huang 	/* pmu_cru_pwr_conx */
753036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), WITH_16BITS_WMSK(pmu1cru_pwr_con));
754036935a8SXiaoDong Huang 
755036935a8SXiaoDong Huang 	/* pmu_ddr_pwr_con */
756036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_DDR_RET_CON(1), 0xffff0000);
757036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), WITH_16BITS_WMSK(pmu1_ddr_pwr_con));
758036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), WITH_16BITS_WMSK(pmu1_ddr_pwr_con));
759036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0x03ff03ff);
760036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0x03ff03ff);
761036935a8SXiaoDong Huang 
762036935a8SXiaoDong Huang 	/* pll_pd */
763036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), WITH_16BITS_WMSK(pmu1_pll_pd_con));
764036935a8SXiaoDong Huang 
765036935a8SXiaoDong Huang 	/* bus idle */
766036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), WITH_16BITS_WMSK(pmu2_bus_idle_con[0]));
767036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), WITH_16BITS_WMSK(pmu2_bus_idle_con[1]));
768036935a8SXiaoDong Huang 
769036935a8SXiaoDong Huang 	/* power gate */
770036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), WITH_16BITS_WMSK(pmu2_pwr_gt_con[0]));
771036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), WITH_16BITS_WMSK(pmu2_pwr_gt_con[1]));
772036935a8SXiaoDong Huang 
773036935a8SXiaoDong Huang 	/* vol gate */
774036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0031);
775036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0200);
776036935a8SXiaoDong Huang 
777036935a8SXiaoDong Huang 	/* wakeup source */
778036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, pmu1_wkup_int_con);
779036935a8SXiaoDong Huang 
780036935a8SXiaoDong Huang 	/* ppll clamp */
781036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5), 0x00400040);
782036935a8SXiaoDong Huang 
783036935a8SXiaoDong Huang 	/* usbphy clamp */
784036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5),
785036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x9, 0x9, 2));
786036935a8SXiaoDong Huang 
787036935a8SXiaoDong Huang 	/* big core pwr ack bypass */
788036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0), 0x01000100);
789036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0), 0x01000100);
790036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0), 0x01000100);
791036935a8SXiaoDong Huang }
792036935a8SXiaoDong Huang 
793036935a8SXiaoDong Huang static void pmu_sleep_restore(void)
794036935a8SXiaoDong Huang {
795036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU0_INFO_TX_CON, 0xffff0000);
796036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_DEBUG_INFO_SEL, 0xffff0000);
797036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CLUSTER0_IDLE_CON, 0xffff0000);
798036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_SCU0_PWR_CON, 0xffff0000);
799036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_CCI_PWR_CON, 0xffff0000);
800036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, 0xffff0000);
801036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PWR_CON, 0xffff0000);
802036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON(0), 0xffff0000);
803036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(0), 0xffff0000);
804036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(1), 0xffff0000);
805036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(0), 0xffff0000);
806036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_DDR_AXIPWR_CON(1), 0xffff0000);
807036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0), 0xffff0000);
808036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0), 0xffff0000);
809036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1), 0xffff0000);
810036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0), 0xffff0000);
811036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1), 0xffff0000);
812036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0), 0xffff0000);
813036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(1), 0xffff0000);
814036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BUS_IDLEACK_BYPASS_CON, 0xffff0000);
815036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, 0);
816036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_FAST_POWER_CON,
817036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_fast_pwr_con));
818036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BISR_GLB_CON,
819036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_bisr_glb_con));
820036935a8SXiaoDong Huang 
821036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C0_PWRACK_BYPASS_CON(0),
822036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_c0_ack_sel_con0));
823036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C1_PWRACK_BYPASS_CON(0),
824036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_c1_ack_sel_con0));
825036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_C2_PWRACK_BYPASS_CON(0),
826036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu2_c2_ack_sel_con0));
827036935a8SXiaoDong Huang 
828036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(5),
829036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con5));
830036935a8SXiaoDong Huang }
831036935a8SXiaoDong Huang 
832036935a8SXiaoDong Huang static void secure_watchdog_disable(void)
833036935a8SXiaoDong Huang {
834036935a8SXiaoDong Huang 	ddr_data.sys_sgrf_soc_con0 =
835036935a8SXiaoDong Huang 		mmio_read_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0));
836036935a8SXiaoDong Huang 
837036935a8SXiaoDong Huang 	/* pause wdt_s */
838036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0),
839036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, 14));
840036935a8SXiaoDong Huang }
841036935a8SXiaoDong Huang 
842036935a8SXiaoDong Huang static void secure_watchdog_restore(void)
843036935a8SXiaoDong Huang {
844036935a8SXiaoDong Huang 	mmio_write_32(SYS_SGRF_BASE + SYSSGRF_SOC_CON(0),
845036935a8SXiaoDong Huang 		      ddr_data.sys_sgrf_soc_con0 |
846036935a8SXiaoDong Huang 		      BITS_WMSK(0x1, 14));
847036935a8SXiaoDong Huang 
848036935a8SXiaoDong Huang 	if (mmio_read_32(WDT_S_BASE + WDT_CR) & WDT_EN)
849036935a8SXiaoDong Huang 		mmio_write_32(WDT_S_BASE + WDT_CRR, 0x76);
850036935a8SXiaoDong Huang }
851036935a8SXiaoDong Huang 
852036935a8SXiaoDong Huang static void soc_sleep_config(void)
853036935a8SXiaoDong Huang {
854036935a8SXiaoDong Huang 	ddr_data.pmu0grf_soc_con0 =
855036935a8SXiaoDong Huang 		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0));
856036935a8SXiaoDong Huang 	ddr_data.pmu0grf_soc_con1 =
857036935a8SXiaoDong Huang 		mmio_read_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1));
858036935a8SXiaoDong Huang 
859036935a8SXiaoDong Huang 	ddr_data.gpio0a_iomux_l =
860036935a8SXiaoDong Huang 		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L);
861036935a8SXiaoDong Huang 	ddr_data.gpio0a_iomux_h =
862036935a8SXiaoDong Huang 		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H);
863036935a8SXiaoDong Huang 	ddr_data.gpio0b_iomux_l =
864036935a8SXiaoDong Huang 		mmio_read_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L);
865036935a8SXiaoDong Huang 
866036935a8SXiaoDong Huang 	sleep_pin_config();
867036935a8SXiaoDong Huang 	pmu_sleep_config();
868036935a8SXiaoDong Huang 	ddr_sleep_config();
869036935a8SXiaoDong Huang 	secure_watchdog_disable();
870036935a8SXiaoDong Huang }
871036935a8SXiaoDong Huang 
872036935a8SXiaoDong Huang static void soc_sleep_restore(void)
873036935a8SXiaoDong Huang {
874036935a8SXiaoDong Huang 	secure_watchdog_restore();
875036935a8SXiaoDong Huang 	ddr_sleep_config_restore();
876036935a8SXiaoDong Huang 	pmu_sleep_restore();
877036935a8SXiaoDong Huang 
878036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_L,
879036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_l));
880036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0A_IOMUX_SEL_H,
881036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_h));
882036935a8SXiaoDong Huang 	mmio_write_32(PMU0_IOC_BASE + PMUIO0_IOC_GPIO0B_IOMUX_SEL_L,
883036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.gpio0b_iomux_l));
884036935a8SXiaoDong Huang 
885036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(1),
886036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con1));
887036935a8SXiaoDong Huang 	mmio_write_32(PMU0_GRF_BASE + PMU0GRF_SOC_CON(0),
888036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con0));
889036935a8SXiaoDong Huang }
890036935a8SXiaoDong Huang 
891036935a8SXiaoDong Huang static void pm_pll_suspend(void)
892036935a8SXiaoDong Huang {
893036935a8SXiaoDong Huang 	ddr_data.cru_mode_con = mmio_read_32(CRU_BASE + 0x280);
894036935a8SXiaoDong Huang 	ddr_data.secure_cru_mode = mmio_read_32(SECURE_CRU_BASE + 0x4280);
895036935a8SXiaoDong Huang 
896036935a8SXiaoDong Huang 	/* bpll gpll vpll aupll cpll spll switch to slow mode */
897036935a8SXiaoDong Huang 	mmio_write_32(CRU_BASE + 0x280, 0x03ff0000);
898036935a8SXiaoDong Huang 	mmio_write_32(SECURE_CRU_BASE + 0x4280, 0x00030000);
899036935a8SXiaoDong Huang 
900036935a8SXiaoDong Huang 	/* hclk_pmu_cm0_root_i_sel to 24M */
901036935a8SXiaoDong Huang 	mmio_write_32(PMU1_CRU_BASE + PMU1CRU_CLKSEL_CON(4),
902036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x3, 0x3, 2));
903036935a8SXiaoDong Huang }
904036935a8SXiaoDong Huang 
905036935a8SXiaoDong Huang static void pm_pll_restore(void)
906036935a8SXiaoDong Huang {
907036935a8SXiaoDong Huang 	mmio_write_32(CRU_BASE + 0x280, WITH_16BITS_WMSK(ddr_data.cru_mode_con));
908036935a8SXiaoDong Huang 	mmio_write_32(SECURE_CRU_BASE + 0x4280,
909036935a8SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.secure_cru_mode));
910036935a8SXiaoDong Huang }
911036935a8SXiaoDong Huang 
912036935a8SXiaoDong Huang int rockchip_soc_sys_pwr_dm_suspend(void)
913036935a8SXiaoDong Huang {
914036935a8SXiaoDong Huang 	psram_sleep_cfg->pm_flag &= ~PM_WARM_BOOT_BIT;
915036935a8SXiaoDong Huang 
916036935a8SXiaoDong Huang 	clk_gate_con_save();
917036935a8SXiaoDong Huang 	clk_gate_con_disable();
918036935a8SXiaoDong Huang 	dmc_save();
919036935a8SXiaoDong Huang 	pmu_power_domains_suspend();
920036935a8SXiaoDong Huang 	soc_sleep_config();
921036935a8SXiaoDong Huang 	pm_pll_suspend();
922036935a8SXiaoDong Huang 	pd_core_save();
923036935a8SXiaoDong Huang 
924036935a8SXiaoDong Huang 	return 0;
925036935a8SXiaoDong Huang }
926036935a8SXiaoDong Huang 
927036935a8SXiaoDong Huang int rockchip_soc_sys_pwr_dm_resume(void)
928036935a8SXiaoDong Huang {
929036935a8SXiaoDong Huang 	pd_core_restore();
930036935a8SXiaoDong Huang 	pm_pll_restore();
931036935a8SXiaoDong Huang 	soc_sleep_restore();
932036935a8SXiaoDong Huang 	pmu_power_domains_resume();
933036935a8SXiaoDong Huang 	plat_rockchip_gic_cpuif_enable();
934036935a8SXiaoDong Huang 	dmc_restore();
935036935a8SXiaoDong Huang 	clk_gate_con_restore();
936036935a8SXiaoDong Huang 
937036935a8SXiaoDong Huang 	psram_sleep_cfg->pm_flag |= PM_WARM_BOOT_BIT;
938036935a8SXiaoDong Huang 
939036935a8SXiaoDong Huang 	return 0;
940036935a8SXiaoDong Huang }
941036935a8SXiaoDong Huang 
942036935a8SXiaoDong Huang static int rockchip_reboot_is_rbrom(void)
943036935a8SXiaoDong Huang {
944036935a8SXiaoDong Huang 	return mmio_read_32(PMU0_GRF_BASE + PMU0GRF_OS_REG(16)) ==
945036935a8SXiaoDong Huang 	       BOOT_BROM_DOWNLOAD;
946036935a8SXiaoDong Huang }
947036935a8SXiaoDong Huang 
948036935a8SXiaoDong Huang static void rockchip_soc_soft_reset_check_rstout(void)
949036935a8SXiaoDong Huang {
950036935a8SXiaoDong Huang 	/*
951036935a8SXiaoDong Huang 	 * Maskrom enter maskrom-usb mode according to os_reg0 which
952036935a8SXiaoDong Huang 	 * will be reset by NPOR. So disable tsadc_shut_m0 if we want
953036935a8SXiaoDong Huang 	 * to maskrom-usb mode.
954036935a8SXiaoDong Huang 	 */
955036935a8SXiaoDong Huang 	if (rockchip_reboot_is_rbrom() != 0) {
956036935a8SXiaoDong Huang 		/* write BOOT_BROM_DOWNLOAD to os_reg0 */
957036935a8SXiaoDong Huang 		mmio_write_32(PMU1_GRF_BASE + PMU1GRF_OS_REG(0), BOOT_BROM_DOWNLOAD);
958036935a8SXiaoDong Huang 
959036935a8SXiaoDong Huang 		/* disable first/tsadc/wdt reset output */
960036935a8SXiaoDong Huang 		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(0), 0x00070000);
961036935a8SXiaoDong Huang 
962036935a8SXiaoDong Huang 		/* clear reset hold */
963036935a8SXiaoDong Huang 		mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(1), 0xffff0000);
964036935a8SXiaoDong Huang 		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(16), 0xffff0000);
965036935a8SXiaoDong Huang 		mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(17), 0xffff0000);
966036935a8SXiaoDong Huang 	}
967036935a8SXiaoDong Huang }
968036935a8SXiaoDong Huang 
969036935a8SXiaoDong Huang void __dead2 rockchip_soc_soft_reset(void)
970036935a8SXiaoDong Huang {
971036935a8SXiaoDong Huang 	rockchip_soc_soft_reset_check_rstout();
972036935a8SXiaoDong Huang 
973036935a8SXiaoDong Huang 	/* pll slow mode */
974036935a8SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_MODE_CON, 0x003f0000);
975036935a8SXiaoDong Huang 
976036935a8SXiaoDong Huang 	dsb();
977036935a8SXiaoDong Huang 	isb();
978036935a8SXiaoDong Huang 
979036935a8SXiaoDong Huang 	INFO("system reset......\n");
980036935a8SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL);
981036935a8SXiaoDong Huang 
982036935a8SXiaoDong Huang 	/*
983036935a8SXiaoDong Huang 	 * Maybe the HW needs some times to reset the system,
984036935a8SXiaoDong Huang 	 * so we do not hope the core to execute valid codes.
985036935a8SXiaoDong Huang 	 */
986*1ed77d1bSBoyan Karatotev 	while (1) {
987*1ed77d1bSBoyan Karatotev 		wfi();
988*1ed77d1bSBoyan Karatotev 	}
989036935a8SXiaoDong Huang }
990036935a8SXiaoDong Huang 
991036935a8SXiaoDong Huang void __dead2 rockchip_soc_system_off(void)
992036935a8SXiaoDong Huang {
993036935a8SXiaoDong Huang 	INFO("system poweroff......\n");
994036935a8SXiaoDong Huang 
995036935a8SXiaoDong Huang 	/* gpio0_a3 config output */
996036935a8SXiaoDong Huang 	mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DDR_L,
997036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, 3));
998036935a8SXiaoDong Huang 
999036935a8SXiaoDong Huang 	/* gpio0_a3 config output high level */
1000036935a8SXiaoDong Huang 	mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DR_L,
1001036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, 3));
1002036935a8SXiaoDong Huang 	dsb();
1003036935a8SXiaoDong Huang 
1004036935a8SXiaoDong Huang 	/*
1005036935a8SXiaoDong Huang 	 * Maybe the HW needs some times to reset the system,
1006036935a8SXiaoDong Huang 	 * so we do not hope the core to execute valid codes.
1007036935a8SXiaoDong Huang 	 */
1008*1ed77d1bSBoyan Karatotev 	while (1) {
1009*1ed77d1bSBoyan Karatotev 		wfi();
1010*1ed77d1bSBoyan Karatotev 	}
1011036935a8SXiaoDong Huang }
1012036935a8SXiaoDong Huang 
1013036935a8SXiaoDong Huang static void rockchip_pmu_pd_repair_init(void)
1014036935a8SXiaoDong Huang {
1015036935a8SXiaoDong Huang 	INFO("enable memory repair\n");
1016036935a8SXiaoDong Huang 	/* Enable gpu and npu repair */
1017036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_BISR_PDGEN_CON(1),
1018036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0xf, 0xf, 6));
1019036935a8SXiaoDong Huang }
1020036935a8SXiaoDong Huang 
1021036935a8SXiaoDong Huang void plat_rockchip_pmu_init(void)
1022036935a8SXiaoDong Huang {
1023036935a8SXiaoDong Huang 	int cpu;
1024036935a8SXiaoDong Huang 
1025036935a8SXiaoDong Huang 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
1026036935a8SXiaoDong Huang 		cpuson_flags[cpu] = 0;
1027036935a8SXiaoDong Huang 
1028036935a8SXiaoDong Huang 	psram_sleep_cfg->sp = PSRAM_SP_TOP;
1029036935a8SXiaoDong Huang 	psram_sleep_cfg->ddr_func = (uint64_t)ddr_resume;
1030036935a8SXiaoDong Huang 	psram_sleep_cfg->ddr_data = 0;
1031036935a8SXiaoDong Huang 	psram_sleep_cfg->ddr_flag = 0;
1032036935a8SXiaoDong Huang 	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
1033036935a8SXiaoDong Huang 	psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT;
1034036935a8SXiaoDong Huang 
1035036935a8SXiaoDong Huang 	nonboot_cpus_off();
1036036935a8SXiaoDong Huang 
1037036935a8SXiaoDong Huang 	/*
1038036935a8SXiaoDong Huang 	 * When perform idle operation, corresponding clock can be
1039036935a8SXiaoDong Huang 	 * opened or gated automatically.
1040036935a8SXiaoDong Huang 	 */
1041036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(0), 0xffffffff);
1042036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_NOC_AUTO_CON(1), 0xffffffff);
1043036935a8SXiaoDong Huang 
1044036935a8SXiaoDong Huang 	/* remap pmusram to 0x00000000 */
1045036935a8SXiaoDong Huang 	mmio_write_32(PMU0SGRF_BASE + PMU0SGRF_SOC_CON(2), BITS_WITH_WMASK(1, 0x3, 0));
1046036935a8SXiaoDong Huang 
1047036935a8SXiaoDong Huang 	/* enable power off VD_NPU by hrdware */
1048036935a8SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_SFTCON(0),
1049036935a8SXiaoDong Huang 		      BITS_WITH_WMASK(0x1, 0x1, 0));
1050036935a8SXiaoDong Huang 
1051036935a8SXiaoDong Huang 	rockchip_pmu_pd_repair_init();
1052036935a8SXiaoDong Huang 
1053036935a8SXiaoDong Huang 	pm_reg_rgns_init();
1054036935a8SXiaoDong Huang }
1055