xref: /rk3399_ARM-atf/plat/rockchip/px30/drivers/pmu/pmu.c (revision d2483afac92c952b969c4443e3a9ae65bcbb485d)
1010d6ae3SXiaoDong Huang /*
2010d6ae3SXiaoDong Huang  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
3010d6ae3SXiaoDong Huang  *
4010d6ae3SXiaoDong Huang  * SPDX-License-Identifier: BSD-3-Clause
5010d6ae3SXiaoDong Huang  */
6010d6ae3SXiaoDong Huang 
7010d6ae3SXiaoDong Huang #include <assert.h>
8010d6ae3SXiaoDong Huang #include <errno.h>
9010d6ae3SXiaoDong Huang 
10010d6ae3SXiaoDong Huang #include <platform_def.h>
11010d6ae3SXiaoDong Huang 
12010d6ae3SXiaoDong Huang #include <arch_helpers.h>
13010d6ae3SXiaoDong Huang #include <bl31/bl31.h>
14010d6ae3SXiaoDong Huang #include <common/debug.h>
15010d6ae3SXiaoDong Huang #include <drivers/console.h>
16010d6ae3SXiaoDong Huang #include <drivers/delay_timer.h>
17010d6ae3SXiaoDong Huang #include <lib/bakery_lock.h>
18010d6ae3SXiaoDong Huang #include <lib/mmio.h>
19010d6ae3SXiaoDong Huang #include <plat/common/platform.h>
20010d6ae3SXiaoDong Huang 
21010d6ae3SXiaoDong Huang #include <cpus_on_fixed_addr.h>
22010d6ae3SXiaoDong Huang #include <plat_private.h>
23010d6ae3SXiaoDong Huang #include <pmu.h>
24010d6ae3SXiaoDong Huang #include <px30_def.h>
25*d2483afaSHeiko Stuebner #include <secure.h>
26010d6ae3SXiaoDong Huang #include <soc.h>
27010d6ae3SXiaoDong Huang 
28010d6ae3SXiaoDong Huang DEFINE_BAKERY_LOCK(rockchip_pd_lock);
29010d6ae3SXiaoDong Huang #define rockchip_pd_lock_init()	bakery_lock_init(&rockchip_pd_lock)
30010d6ae3SXiaoDong Huang #define rockchip_pd_lock_get()	bakery_lock_get(&rockchip_pd_lock)
31010d6ae3SXiaoDong Huang #define rockchip_pd_lock_rls()	bakery_lock_release(&rockchip_pd_lock)
32010d6ae3SXiaoDong Huang 
33010d6ae3SXiaoDong Huang static struct psram_data_t *psram_boot_cfg =
34010d6ae3SXiaoDong Huang 	(struct psram_data_t *)&sys_sleep_flag_sram;
35010d6ae3SXiaoDong Huang 
36010d6ae3SXiaoDong Huang /*
37010d6ae3SXiaoDong Huang  * There are two ways to powering on or off on core.
38010d6ae3SXiaoDong Huang  * 1) Control it power domain into on or off in PMU_PWRDN_CON reg,
39010d6ae3SXiaoDong Huang  *    it is core_pwr_pd mode
40010d6ae3SXiaoDong Huang  * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
41010d6ae3SXiaoDong Huang  *     then, if the core enter into wfi, it power domain will be
42010d6ae3SXiaoDong Huang  *     powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode
43010d6ae3SXiaoDong Huang  * so we need core_pm_cfg_info to distinguish which method be used now.
44010d6ae3SXiaoDong Huang  */
45010d6ae3SXiaoDong Huang 
46010d6ae3SXiaoDong Huang static uint32_t cores_pd_cfg_info[PLATFORM_CORE_COUNT]
47010d6ae3SXiaoDong Huang #if USE_COHERENT_MEM
48010d6ae3SXiaoDong Huang __attribute__ ((section("tzfw_coherent_mem")))
49010d6ae3SXiaoDong Huang #endif
50010d6ae3SXiaoDong Huang ;
51010d6ae3SXiaoDong Huang 
52010d6ae3SXiaoDong Huang struct px30_sleep_ddr_data {
53010d6ae3SXiaoDong Huang 	uint32_t clk_sel0;
54010d6ae3SXiaoDong Huang 	uint32_t cru_mode_save;
55010d6ae3SXiaoDong Huang 	uint32_t cru_pmu_mode_save;
56010d6ae3SXiaoDong Huang 	uint32_t ddrc_hwlpctl;
57010d6ae3SXiaoDong Huang 	uint32_t ddrc_pwrctrl;
58010d6ae3SXiaoDong Huang 	uint32_t ddrgrf_con0;
59010d6ae3SXiaoDong Huang 	uint32_t ddrgrf_con1;
60010d6ae3SXiaoDong Huang 	uint32_t ddrstdby_con0;
61010d6ae3SXiaoDong Huang 	uint32_t gpio0b_iomux;
62010d6ae3SXiaoDong Huang 	uint32_t gpio0c_iomux;
63010d6ae3SXiaoDong Huang 	uint32_t pmu_pwrmd_core_l;
64010d6ae3SXiaoDong Huang 	uint32_t pmu_pwrmd_core_h;
65010d6ae3SXiaoDong Huang 	uint32_t pmu_pwrmd_cmm_l;
66010d6ae3SXiaoDong Huang 	uint32_t pmu_pwrmd_cmm_h;
67010d6ae3SXiaoDong Huang 	uint32_t pmu_wkup_cfg2_l;
68010d6ae3SXiaoDong Huang 	uint32_t pmu_cru_clksel_con0;
69010d6ae3SXiaoDong Huang 	uint32_t pmugrf_soc_con0;
70010d6ae3SXiaoDong Huang 	uint32_t pmusgrf_soc_con0;
71010d6ae3SXiaoDong Huang 	uint32_t pmic_slp_iomux;
72010d6ae3SXiaoDong Huang 	uint32_t pgrf_pvtm_con[2];
73010d6ae3SXiaoDong Huang 	uint32_t cru_clk_gate[CRU_CLKGATES_CON_CNT];
74010d6ae3SXiaoDong Huang 	uint32_t cru_pmu_clk_gate[CRU_PMU_CLKGATE_CON_CNT];
75010d6ae3SXiaoDong Huang 	uint32_t cru_plls_con_save[END_PLL_ID][PLL_CON_CNT];
76010d6ae3SXiaoDong Huang 	uint32_t cpu_qos[CPU_AXI_QOS_NUM_REGS];
77010d6ae3SXiaoDong Huang 	uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS];
78010d6ae3SXiaoDong Huang 	uint32_t isp_128m_qos[CPU_AXI_QOS_NUM_REGS];
79010d6ae3SXiaoDong Huang 	uint32_t isp_rd_qos[CPU_AXI_QOS_NUM_REGS];
80010d6ae3SXiaoDong Huang 	uint32_t isp_wr_qos[CPU_AXI_QOS_NUM_REGS];
81010d6ae3SXiaoDong Huang 	uint32_t isp_m1_qos[CPU_AXI_QOS_NUM_REGS];
82010d6ae3SXiaoDong Huang 	uint32_t vip_qos[CPU_AXI_QOS_NUM_REGS];
83010d6ae3SXiaoDong Huang 	uint32_t rga_rd_qos[CPU_AXI_QOS_NUM_REGS];
84010d6ae3SXiaoDong Huang 	uint32_t rga_wr_qos[CPU_AXI_QOS_NUM_REGS];
85010d6ae3SXiaoDong Huang 	uint32_t vop_m0_qos[CPU_AXI_QOS_NUM_REGS];
86010d6ae3SXiaoDong Huang 	uint32_t vop_m1_qos[CPU_AXI_QOS_NUM_REGS];
87010d6ae3SXiaoDong Huang 	uint32_t vpu_qos[CPU_AXI_QOS_NUM_REGS];
88010d6ae3SXiaoDong Huang 	uint32_t vpu_r128_qos[CPU_AXI_QOS_NUM_REGS];
89010d6ae3SXiaoDong Huang 	uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS];
90010d6ae3SXiaoDong Huang 	uint32_t dmac_qos[CPU_AXI_QOS_NUM_REGS];
91010d6ae3SXiaoDong Huang 	uint32_t crypto_qos[CPU_AXI_QOS_NUM_REGS];
92010d6ae3SXiaoDong Huang 	uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS];
93010d6ae3SXiaoDong Huang 	uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS];
94010d6ae3SXiaoDong Huang 	uint32_t nand_qos[CPU_AXI_QOS_NUM_REGS];
95010d6ae3SXiaoDong Huang 	uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS];
96010d6ae3SXiaoDong Huang 	uint32_t sfc_qos[CPU_AXI_QOS_NUM_REGS];
97010d6ae3SXiaoDong Huang 	uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS];
98010d6ae3SXiaoDong Huang 	uint32_t usb_host_qos[CPU_AXI_QOS_NUM_REGS];
99010d6ae3SXiaoDong Huang 	uint32_t usb_otg_qos[CPU_AXI_QOS_NUM_REGS];
100010d6ae3SXiaoDong Huang };
101010d6ae3SXiaoDong Huang 
102010d6ae3SXiaoDong Huang static struct px30_sleep_ddr_data ddr_data
103010d6ae3SXiaoDong Huang #if USE_COHERENT_MEM
104010d6ae3SXiaoDong Huang __attribute__ ((section("tzfw_coherent_mem")))
105010d6ae3SXiaoDong Huang #endif
106010d6ae3SXiaoDong Huang ;
107010d6ae3SXiaoDong Huang 
108010d6ae3SXiaoDong Huang static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
109010d6ae3SXiaoDong Huang {
110010d6ae3SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
111010d6ae3SXiaoDong Huang 	return cores_pd_cfg_info[cpu_id];
112010d6ae3SXiaoDong Huang }
113010d6ae3SXiaoDong Huang 
114010d6ae3SXiaoDong Huang static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
115010d6ae3SXiaoDong Huang {
116010d6ae3SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
117010d6ae3SXiaoDong Huang 	cores_pd_cfg_info[cpu_id] = value;
118010d6ae3SXiaoDong Huang #if !USE_COHERENT_MEM
119010d6ae3SXiaoDong Huang 	flush_dcache_range((uintptr_t)&cores_pd_cfg_info[cpu_id],
120010d6ae3SXiaoDong Huang 			   sizeof(uint32_t));
121010d6ae3SXiaoDong Huang #endif
122010d6ae3SXiaoDong Huang }
123010d6ae3SXiaoDong Huang 
124010d6ae3SXiaoDong Huang static inline uint32_t pmu_power_domain_st(uint32_t pd)
125010d6ae3SXiaoDong Huang {
126010d6ae3SXiaoDong Huang 	return mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd) ?
127010d6ae3SXiaoDong Huang 	       pmu_pd_off :
128010d6ae3SXiaoDong Huang 	       pmu_pd_on;
129010d6ae3SXiaoDong Huang }
130010d6ae3SXiaoDong Huang 
131010d6ae3SXiaoDong Huang static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
132010d6ae3SXiaoDong Huang {
133010d6ae3SXiaoDong Huang 	uint32_t loop = 0;
134010d6ae3SXiaoDong Huang 	int ret = 0;
135010d6ae3SXiaoDong Huang 
136010d6ae3SXiaoDong Huang 	rockchip_pd_lock_get();
137010d6ae3SXiaoDong Huang 
138010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRDN_CON,
139010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(pd_state, 0x1, pd));
140010d6ae3SXiaoDong Huang 	dsb();
141010d6ae3SXiaoDong Huang 
142010d6ae3SXiaoDong Huang 	while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
143010d6ae3SXiaoDong Huang 		udelay(1);
144010d6ae3SXiaoDong Huang 		loop++;
145010d6ae3SXiaoDong Huang 	}
146010d6ae3SXiaoDong Huang 
147010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(pd) != pd_state) {
148010d6ae3SXiaoDong Huang 		WARN("%s: %d, %d, error!\n", __func__, pd, pd_state);
149010d6ae3SXiaoDong Huang 		ret = -EINVAL;
150010d6ae3SXiaoDong Huang 	}
151010d6ae3SXiaoDong Huang 
152010d6ae3SXiaoDong Huang 	rockchip_pd_lock_rls();
153010d6ae3SXiaoDong Huang 
154010d6ae3SXiaoDong Huang 	return ret;
155010d6ae3SXiaoDong Huang }
156010d6ae3SXiaoDong Huang 
157010d6ae3SXiaoDong Huang static inline uint32_t pmu_bus_idle_st(uint32_t bus)
158010d6ae3SXiaoDong Huang {
159010d6ae3SXiaoDong Huang 	return !!((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus)) &&
160010d6ae3SXiaoDong Huang 		  (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus + 16)));
161010d6ae3SXiaoDong Huang }
162010d6ae3SXiaoDong Huang 
163010d6ae3SXiaoDong Huang static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
164010d6ae3SXiaoDong Huang {
165010d6ae3SXiaoDong Huang 	uint32_t wait_cnt = 0;
166010d6ae3SXiaoDong Huang 
167010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_BUS_IDLE_REQ,
168010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(state, 0x1, bus));
169010d6ae3SXiaoDong Huang 
170010d6ae3SXiaoDong Huang 	while (pmu_bus_idle_st(bus) != state &&
171010d6ae3SXiaoDong Huang 	       wait_cnt < BUS_IDLE_LOOP) {
172010d6ae3SXiaoDong Huang 		udelay(1);
173010d6ae3SXiaoDong Huang 		wait_cnt++;
174010d6ae3SXiaoDong Huang 	}
175010d6ae3SXiaoDong Huang 
176010d6ae3SXiaoDong Huang 	if (pmu_bus_idle_st(bus) != state)
177010d6ae3SXiaoDong Huang 		WARN("%s:idle_st=0x%x, bus_id=%d\n",
178010d6ae3SXiaoDong Huang 		     __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST), bus);
179010d6ae3SXiaoDong Huang }
180010d6ae3SXiaoDong Huang 
181010d6ae3SXiaoDong Huang static void qos_save(void)
182010d6ae3SXiaoDong Huang {
183010d6ae3SXiaoDong Huang 	/* scu powerdomain will power off, so cpu qos should be saved */
184010d6ae3SXiaoDong Huang 	SAVE_QOS(ddr_data.cpu_qos, CPU);
185010d6ae3SXiaoDong Huang 
186010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
187010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.gpu_qos, GPU);
188010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VI) == pmu_pd_on) {
189010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.isp_128m_qos, ISP_128M);
190010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.isp_rd_qos, ISP_RD);
191010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.isp_wr_qos, ISP_WR);
192010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.isp_m1_qos, ISP_M1);
193010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vip_qos, VIP);
194010d6ae3SXiaoDong Huang 	}
195010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
196010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.rga_rd_qos, RGA_RD);
197010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.rga_wr_qos, RGA_WR);
198010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vop_m0_qos, VOP_M0);
199010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vop_m1_qos, VOP_M1);
200010d6ae3SXiaoDong Huang 	}
201010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) {
202010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vpu_qos, VPU);
203010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vpu_r128_qos, VPU_R128);
204010d6ae3SXiaoDong Huang 	}
205010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) {
206010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.emmc_qos, EMMC);
207010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.nand_qos, NAND);
208010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.sdio_qos, SDIO);
209010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.sfc_qos, SFC);
210010d6ae3SXiaoDong Huang 	}
211010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
212010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.gmac_qos, GMAC);
213010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on)
214010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.crypto_qos, CRYPTO);
215010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on)
216010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.sdmmc_qos, SDMMC);
217010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_USB) == pmu_pd_on) {
218010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.usb_host_qos, USB_HOST);
219010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.usb_otg_qos, USB_OTG);
220010d6ae3SXiaoDong Huang 	}
221010d6ae3SXiaoDong Huang }
222010d6ae3SXiaoDong Huang 
223010d6ae3SXiaoDong Huang static void qos_restore(void)
224010d6ae3SXiaoDong Huang {
225010d6ae3SXiaoDong Huang 	RESTORE_QOS(ddr_data.cpu_qos, CPU);
226010d6ae3SXiaoDong Huang 
227010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
228010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.gpu_qos, GPU);
229010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VI) == pmu_pd_on) {
230010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.isp_128m_qos, ISP_128M);
231010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.isp_rd_qos, ISP_RD);
232010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.isp_wr_qos, ISP_WR);
233010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.isp_m1_qos, ISP_M1);
234010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vip_qos, VIP);
235010d6ae3SXiaoDong Huang 	}
236010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
237010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.rga_rd_qos, RGA_RD);
238010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.rga_wr_qos, RGA_WR);
239010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vop_m0_qos, VOP_M0);
240010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vop_m1_qos, VOP_M1);
241010d6ae3SXiaoDong Huang 	}
242010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) {
243010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vpu_qos, VPU);
244010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vpu_r128_qos, VPU_R128);
245010d6ae3SXiaoDong Huang 	}
246010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) {
247010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.emmc_qos, EMMC);
248010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.nand_qos, NAND);
249010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.sdio_qos, SDIO);
250010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.sfc_qos, SFC);
251010d6ae3SXiaoDong Huang 	}
252010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
253010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.gmac_qos, GMAC);
254010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on)
255010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.crypto_qos, CRYPTO);
256010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on)
257010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.sdmmc_qos, SDMMC);
258010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_USB) == pmu_pd_on) {
259010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.usb_host_qos, USB_HOST);
260010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.usb_otg_qos, USB_OTG);
261010d6ae3SXiaoDong Huang 	}
262010d6ae3SXiaoDong Huang }
263010d6ae3SXiaoDong Huang 
264010d6ae3SXiaoDong Huang static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
265010d6ae3SXiaoDong Huang {
266010d6ae3SXiaoDong Huang 	uint32_t state;
267010d6ae3SXiaoDong Huang 
268010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(pd_id) == pd_state)
269010d6ae3SXiaoDong Huang 		goto out;
270010d6ae3SXiaoDong Huang 
271010d6ae3SXiaoDong Huang 	if (pd_state == pmu_pd_on)
272010d6ae3SXiaoDong Huang 		pmu_power_domain_ctr(pd_id, pd_state);
273010d6ae3SXiaoDong Huang 
274010d6ae3SXiaoDong Huang 	state = (pd_state == pmu_pd_off) ? bus_idle : bus_active;
275010d6ae3SXiaoDong Huang 
276010d6ae3SXiaoDong Huang 	switch (pd_id) {
277010d6ae3SXiaoDong Huang 	case PD_GPU:
278010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_GPU, state);
279010d6ae3SXiaoDong Huang 		break;
280010d6ae3SXiaoDong Huang 	case PD_VI:
281010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_VI, state);
282010d6ae3SXiaoDong Huang 		break;
283010d6ae3SXiaoDong Huang 	case PD_VO:
284010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_VO, state);
285010d6ae3SXiaoDong Huang 		break;
286010d6ae3SXiaoDong Huang 	case PD_VPU:
287010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_VPU, state);
288010d6ae3SXiaoDong Huang 		break;
289010d6ae3SXiaoDong Huang 	case PD_MMC_NAND:
290010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_MMC, state);
291010d6ae3SXiaoDong Huang 		break;
292010d6ae3SXiaoDong Huang 	case PD_GMAC:
293010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_GMAC, state);
294010d6ae3SXiaoDong Huang 		break;
295010d6ae3SXiaoDong Huang 	case PD_CRYPTO:
296010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_CRYPTO, state);
297010d6ae3SXiaoDong Huang 		break;
298010d6ae3SXiaoDong Huang 	case PD_SDCARD:
299010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_SDCARD, state);
300010d6ae3SXiaoDong Huang 		break;
301010d6ae3SXiaoDong Huang 	case PD_USB:
302010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_USB, state);
303010d6ae3SXiaoDong Huang 		break;
304010d6ae3SXiaoDong Huang 	default:
305010d6ae3SXiaoDong Huang 		break;
306010d6ae3SXiaoDong Huang 	}
307010d6ae3SXiaoDong Huang 
308010d6ae3SXiaoDong Huang 	if (pd_state == pmu_pd_off)
309010d6ae3SXiaoDong Huang 		pmu_power_domain_ctr(pd_id, pd_state);
310010d6ae3SXiaoDong Huang 
311010d6ae3SXiaoDong Huang out:
312010d6ae3SXiaoDong Huang 	return 0;
313010d6ae3SXiaoDong Huang }
314010d6ae3SXiaoDong Huang 
315010d6ae3SXiaoDong Huang static uint32_t pmu_powerdomain_state;
316010d6ae3SXiaoDong Huang 
317010d6ae3SXiaoDong Huang static void pmu_power_domains_suspend(void)
318010d6ae3SXiaoDong Huang {
319010d6ae3SXiaoDong Huang 	uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT];
320010d6ae3SXiaoDong Huang 
321010d6ae3SXiaoDong Huang 	clk_gate_con_save(clkgt_save);
322010d6ae3SXiaoDong Huang 	clk_gate_con_disable();
323010d6ae3SXiaoDong Huang 	qos_save();
324010d6ae3SXiaoDong Huang 
325010d6ae3SXiaoDong Huang 	pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
326010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_GPU, pmu_pd_off);
327010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_VI, pmu_pd_off);
328010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_VO, pmu_pd_off);
329010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_VPU, pmu_pd_off);
330010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_MMC_NAND, pmu_pd_off);
331010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_GMAC, pmu_pd_off);
332010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_CRYPTO, pmu_pd_off);
333010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_SDCARD, pmu_pd_off);
334010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_USB, pmu_pd_off);
335010d6ae3SXiaoDong Huang 
336010d6ae3SXiaoDong Huang 	clk_gate_con_restore(clkgt_save);
337010d6ae3SXiaoDong Huang }
338010d6ae3SXiaoDong Huang 
339010d6ae3SXiaoDong Huang static void pmu_power_domains_resume(void)
340010d6ae3SXiaoDong Huang {
341010d6ae3SXiaoDong Huang 	uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT];
342010d6ae3SXiaoDong Huang 
343010d6ae3SXiaoDong Huang 	clk_gate_con_save(clkgt_save);
344010d6ae3SXiaoDong Huang 	clk_gate_con_disable();
345010d6ae3SXiaoDong Huang 
346010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_USB)))
347010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_USB, pmu_pd_on);
348010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_SDCARD)))
349010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_SDCARD, pmu_pd_on);
350010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_CRYPTO)))
351010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_CRYPTO, pmu_pd_on);
352010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_GMAC)))
353010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_GMAC, pmu_pd_on);
354010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_MMC_NAND)))
355010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_MMC_NAND, pmu_pd_on);
356010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_VPU)))
357010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_VPU, pmu_pd_on);
358010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_VO)))
359010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_VO, pmu_pd_on);
360010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_VI)))
361010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_VI, pmu_pd_on);
362010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_GPU)))
363010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_GPU, pmu_pd_on);
364010d6ae3SXiaoDong Huang 
365010d6ae3SXiaoDong Huang 	qos_restore();
366010d6ae3SXiaoDong Huang 	clk_gate_con_restore(clkgt_save);
367010d6ae3SXiaoDong Huang }
368010d6ae3SXiaoDong Huang 
369010d6ae3SXiaoDong Huang static int check_cpu_wfie(uint32_t cpu)
370010d6ae3SXiaoDong Huang {
371010d6ae3SXiaoDong Huang 	uint32_t loop = 0, wfie_msk = CKECK_WFEI_MSK << cpu;
372010d6ae3SXiaoDong Huang 
373010d6ae3SXiaoDong Huang 	while (!(mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) &&
374010d6ae3SXiaoDong Huang 	       (loop < WFEI_CHECK_LOOP)) {
375010d6ae3SXiaoDong Huang 		udelay(1);
376010d6ae3SXiaoDong Huang 		loop++;
377010d6ae3SXiaoDong Huang 	}
378010d6ae3SXiaoDong Huang 
379010d6ae3SXiaoDong Huang 	if ((mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) == 0) {
380010d6ae3SXiaoDong Huang 		WARN("%s: %d, %d, error!\n", __func__, cpu, wfie_msk);
381010d6ae3SXiaoDong Huang 		return -EINVAL;
382010d6ae3SXiaoDong Huang 	}
383010d6ae3SXiaoDong Huang 
384010d6ae3SXiaoDong Huang 	return 0;
385010d6ae3SXiaoDong Huang }
386010d6ae3SXiaoDong Huang 
387010d6ae3SXiaoDong Huang static int cpus_power_domain_on(uint32_t cpu_id)
388010d6ae3SXiaoDong Huang {
389010d6ae3SXiaoDong Huang 	uint32_t cpu_pd, apm_value, cfg_info, loop = 0;
390010d6ae3SXiaoDong Huang 
391010d6ae3SXiaoDong Huang 	cpu_pd = PD_CPU0 + cpu_id;
392010d6ae3SXiaoDong Huang 	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
393010d6ae3SXiaoDong Huang 
394010d6ae3SXiaoDong Huang 	if (cfg_info == core_pwr_pd) {
395010d6ae3SXiaoDong Huang 		/* disable apm cfg */
396010d6ae3SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
397010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(CORES_PM_DISABLE));
398010d6ae3SXiaoDong Huang 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
399010d6ae3SXiaoDong Huang 			mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
400010d6ae3SXiaoDong Huang 				      WITH_16BITS_WMSK(CORES_PM_DISABLE));
401010d6ae3SXiaoDong Huang 			pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
402010d6ae3SXiaoDong Huang 		}
403010d6ae3SXiaoDong Huang 		pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
404010d6ae3SXiaoDong Huang 	} else {
405010d6ae3SXiaoDong Huang 		/* wait cpu down */
406010d6ae3SXiaoDong Huang 		while (pmu_power_domain_st(cpu_pd) == pmu_pd_on && loop < 100) {
407010d6ae3SXiaoDong Huang 			udelay(2);
408010d6ae3SXiaoDong Huang 			loop++;
409010d6ae3SXiaoDong Huang 		}
410010d6ae3SXiaoDong Huang 
411010d6ae3SXiaoDong Huang 		/* return error if can't wait cpu down */
412010d6ae3SXiaoDong Huang 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
413010d6ae3SXiaoDong Huang 			WARN("%s:can't wait cpu down\n", __func__);
414010d6ae3SXiaoDong Huang 			return -EINVAL;
415010d6ae3SXiaoDong Huang 		}
416010d6ae3SXiaoDong Huang 
417010d6ae3SXiaoDong Huang 		/* power up cpu in power down state */
418010d6ae3SXiaoDong Huang 		apm_value = BIT(core_pm_sft_wakeup_en);
419010d6ae3SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
420010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(apm_value));
421010d6ae3SXiaoDong Huang 	}
422010d6ae3SXiaoDong Huang 
423010d6ae3SXiaoDong Huang 	return 0;
424010d6ae3SXiaoDong Huang }
425010d6ae3SXiaoDong Huang 
426010d6ae3SXiaoDong Huang static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
427010d6ae3SXiaoDong Huang {
428010d6ae3SXiaoDong Huang 	uint32_t cpu_pd, apm_value;
429010d6ae3SXiaoDong Huang 
430010d6ae3SXiaoDong Huang 	cpu_pd = PD_CPU0 + cpu_id;
431010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
432010d6ae3SXiaoDong Huang 		return 0;
433010d6ae3SXiaoDong Huang 
434010d6ae3SXiaoDong Huang 	if (pd_cfg == core_pwr_pd) {
435010d6ae3SXiaoDong Huang 		if (check_cpu_wfie(cpu_id))
436010d6ae3SXiaoDong Huang 			return -EINVAL;
437010d6ae3SXiaoDong Huang 		/* disable apm cfg */
438010d6ae3SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
439010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(CORES_PM_DISABLE));
440010d6ae3SXiaoDong Huang 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
441010d6ae3SXiaoDong Huang 		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
442010d6ae3SXiaoDong Huang 	} else {
443010d6ae3SXiaoDong Huang 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
444010d6ae3SXiaoDong Huang 		apm_value = BIT(core_pm_en) | BIT(core_pm_dis_int);
445010d6ae3SXiaoDong Huang 		if (pd_cfg == core_pwr_wfi_int)
446010d6ae3SXiaoDong Huang 			apm_value |= BIT(core_pm_int_wakeup_en);
447010d6ae3SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
448010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(apm_value));
449010d6ae3SXiaoDong Huang 	}
450010d6ae3SXiaoDong Huang 
451010d6ae3SXiaoDong Huang 	return 0;
452010d6ae3SXiaoDong Huang }
453010d6ae3SXiaoDong Huang 
454010d6ae3SXiaoDong Huang static void nonboot_cpus_off(void)
455010d6ae3SXiaoDong Huang {
456010d6ae3SXiaoDong Huang 	uint32_t boot_cpu, cpu;
457010d6ae3SXiaoDong Huang 
458010d6ae3SXiaoDong Huang 	boot_cpu = plat_my_core_pos();
459010d6ae3SXiaoDong Huang 
460010d6ae3SXiaoDong Huang 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
461010d6ae3SXiaoDong Huang 		if (cpu == boot_cpu)
462010d6ae3SXiaoDong Huang 			continue;
463010d6ae3SXiaoDong Huang 		cpus_power_domain_off(cpu, core_pwr_pd);
464010d6ae3SXiaoDong Huang 	}
465010d6ae3SXiaoDong Huang }
466010d6ae3SXiaoDong Huang 
467010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr,
468010d6ae3SXiaoDong Huang 				 uint64_t entrypoint)
469010d6ae3SXiaoDong Huang {
470010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
471010d6ae3SXiaoDong Huang 
472010d6ae3SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
473010d6ae3SXiaoDong Huang 	assert(cpuson_flags[cpu_id] == 0);
474010d6ae3SXiaoDong Huang 	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
475010d6ae3SXiaoDong Huang 	cpuson_entry_point[cpu_id] = entrypoint;
476010d6ae3SXiaoDong Huang 	dsb();
477010d6ae3SXiaoDong Huang 
478010d6ae3SXiaoDong Huang 	cpus_power_domain_on(cpu_id);
479010d6ae3SXiaoDong Huang 
480010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
481010d6ae3SXiaoDong Huang }
482010d6ae3SXiaoDong Huang 
483010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on_finish(void)
484010d6ae3SXiaoDong Huang {
485010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
486010d6ae3SXiaoDong Huang 
487010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
488010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(CORES_PM_DISABLE));
489010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
490010d6ae3SXiaoDong Huang }
491010d6ae3SXiaoDong Huang 
492010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_off(void)
493010d6ae3SXiaoDong Huang {
494010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
495010d6ae3SXiaoDong Huang 
496010d6ae3SXiaoDong Huang 	cpus_power_domain_off(cpu_id, core_pwr_wfi);
497010d6ae3SXiaoDong Huang 
498010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
499010d6ae3SXiaoDong Huang }
500010d6ae3SXiaoDong Huang 
501010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_suspend(void)
502010d6ae3SXiaoDong Huang {
503010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
504010d6ae3SXiaoDong Huang 
505010d6ae3SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
506010d6ae3SXiaoDong Huang 	assert(cpuson_flags[cpu_id] == 0);
507010d6ae3SXiaoDong Huang 	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
508010d6ae3SXiaoDong Huang 	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
509010d6ae3SXiaoDong Huang 	dsb();
510010d6ae3SXiaoDong Huang 
511010d6ae3SXiaoDong Huang 	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
512010d6ae3SXiaoDong Huang 
513010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
514010d6ae3SXiaoDong Huang }
515010d6ae3SXiaoDong Huang 
516010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_resume(void)
517010d6ae3SXiaoDong Huang {
518010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
519010d6ae3SXiaoDong Huang 
520010d6ae3SXiaoDong Huang 	/* Disable core_pm */
521010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
522010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(CORES_PM_DISABLE));
523010d6ae3SXiaoDong Huang 
524010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
525010d6ae3SXiaoDong Huang }
526010d6ae3SXiaoDong Huang 
527010d6ae3SXiaoDong Huang #define CLK_MSK_GATING(msk, con) \
528010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + (con), ((msk) << 16) | 0xffff)
529010d6ae3SXiaoDong Huang #define CLK_MSK_UNGATING(msk, con) \
530010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + (con), ((~(msk)) << 16) | 0xffff)
531010d6ae3SXiaoDong Huang 
532010d6ae3SXiaoDong Huang static uint32_t clk_ungt_msk[CRU_CLKGATES_CON_CNT] = {
533010d6ae3SXiaoDong Huang 	0xe0ff, 0xffff, 0x0000, 0x0000,
534010d6ae3SXiaoDong Huang 	0x0000, 0x0380, 0x0000, 0x0000,
535010d6ae3SXiaoDong Huang 	0x07c0, 0x0000, 0x0000, 0x000f,
536010d6ae3SXiaoDong Huang 	0x0061, 0x1f02, 0x0440, 0x1801,
537010d6ae3SXiaoDong Huang 	0x004b, 0x0000
538010d6ae3SXiaoDong Huang };
539010d6ae3SXiaoDong Huang 
540010d6ae3SXiaoDong Huang static uint32_t clk_pmu_ungt_msk[CRU_PMU_CLKGATE_CON_CNT] = {
541010d6ae3SXiaoDong Huang 	0xf1ff, 0x0310
542010d6ae3SXiaoDong Huang };
543010d6ae3SXiaoDong Huang 
544010d6ae3SXiaoDong Huang void clk_gate_suspend(void)
545010d6ae3SXiaoDong Huang {
546010d6ae3SXiaoDong Huang 	int i;
547010d6ae3SXiaoDong Huang 
548010d6ae3SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) {
549010d6ae3SXiaoDong Huang 		ddr_data.cru_clk_gate[i] =
550010d6ae3SXiaoDong Huang 			mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
551010d6ae3SXiaoDong Huang 			mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
552010d6ae3SXiaoDong Huang 				      WITH_16BITS_WMSK(~clk_ungt_msk[i]));
553010d6ae3SXiaoDong Huang 	}
554010d6ae3SXiaoDong Huang 
555010d6ae3SXiaoDong Huang 	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) {
556010d6ae3SXiaoDong Huang 		ddr_data.cru_pmu_clk_gate[i] =
557010d6ae3SXiaoDong Huang 			mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i));
558010d6ae3SXiaoDong Huang 			mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
559010d6ae3SXiaoDong Huang 				      WITH_16BITS_WMSK(~clk_pmu_ungt_msk[i]));
560010d6ae3SXiaoDong Huang 	}
561010d6ae3SXiaoDong Huang }
562010d6ae3SXiaoDong Huang 
563010d6ae3SXiaoDong Huang void clk_gate_resume(void)
564010d6ae3SXiaoDong Huang {
565010d6ae3SXiaoDong Huang 	int i;
566010d6ae3SXiaoDong Huang 
567010d6ae3SXiaoDong Huang 	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++)
568010d6ae3SXiaoDong Huang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
569010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(ddr_data.cru_pmu_clk_gate[i]));
570010d6ae3SXiaoDong Huang 
571010d6ae3SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
572010d6ae3SXiaoDong Huang 		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
573010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(ddr_data.cru_clk_gate[i]));
574010d6ae3SXiaoDong Huang }
575010d6ae3SXiaoDong Huang 
576010d6ae3SXiaoDong Huang static void pvtm_32k_config(void)
577010d6ae3SXiaoDong Huang {
578010d6ae3SXiaoDong Huang 	uint32_t  pvtm_freq_khz, pvtm_div;
579010d6ae3SXiaoDong Huang 
580010d6ae3SXiaoDong Huang 	ddr_data.pmu_cru_clksel_con0 =
581010d6ae3SXiaoDong Huang 		mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0));
582010d6ae3SXiaoDong Huang 
583010d6ae3SXiaoDong Huang 	ddr_data.pgrf_pvtm_con[0] =
584010d6ae3SXiaoDong Huang 		mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON0);
585010d6ae3SXiaoDong Huang 	ddr_data.pgrf_pvtm_con[1] =
586010d6ae3SXiaoDong Huang 		mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON1);
587010d6ae3SXiaoDong Huang 
588010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
589010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0x3, pgrf_pvtm_st));
590010d6ae3SXiaoDong Huang 	dsb();
591010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
592010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_en));
593010d6ae3SXiaoDong Huang 	dsb();
594010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, PVTM_CALC_CNT);
595010d6ae3SXiaoDong Huang 	dsb();
596010d6ae3SXiaoDong Huang 
597010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
598010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_st));
599010d6ae3SXiaoDong Huang 
600010d6ae3SXiaoDong Huang 	/* pmugrf_pvtm_st0 will be clear after PVTM start,
601010d6ae3SXiaoDong Huang 	 * which will cost about 6 cycles of pvtm at least.
602010d6ae3SXiaoDong Huang 	 * So we wait 30 cycles of pvtm for security.
603010d6ae3SXiaoDong Huang 	 */
604010d6ae3SXiaoDong Huang 	while (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) < 30)
605010d6ae3SXiaoDong Huang 		;
606010d6ae3SXiaoDong Huang 
607010d6ae3SXiaoDong Huang 	dsb();
608010d6ae3SXiaoDong Huang 	while (!(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST0) & 0x1))
609010d6ae3SXiaoDong Huang 		;
610010d6ae3SXiaoDong Huang 
611010d6ae3SXiaoDong Huang 	pvtm_freq_khz =
612010d6ae3SXiaoDong Huang 		(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) * 24000 +
613010d6ae3SXiaoDong Huang 		PVTM_CALC_CNT / 2) / PVTM_CALC_CNT;
614010d6ae3SXiaoDong Huang 	pvtm_div = (pvtm_freq_khz + 16) / 32;
615010d6ae3SXiaoDong Huang 
616010d6ae3SXiaoDong Huang 	/* pvtm_div = div_factor << 2 + 1,
617010d6ae3SXiaoDong Huang 	 * so div_factor = (pvtm_div - 1) >> 2.
618010d6ae3SXiaoDong Huang 	 * But the operation ">> 2" will clear the low bit of pvtm_div,
619010d6ae3SXiaoDong Huang 	 * so we don't have to do "- 1" for compasation
620010d6ae3SXiaoDong Huang 	 */
621010d6ae3SXiaoDong Huang 	pvtm_div = pvtm_div >> 2;
622010d6ae3SXiaoDong Huang 	if (pvtm_div > 0x3f)
623010d6ae3SXiaoDong Huang 		pvtm_div = 0x3f;
624010d6ae3SXiaoDong Huang 
625010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
626010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(pvtm_div, 0x3f, pgrf_pvtm_div));
627010d6ae3SXiaoDong Huang 
628010d6ae3SXiaoDong Huang 	/* select pvtm as 32k source */
629010d6ae3SXiaoDong Huang 	mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0),
6308a079e88SAmbroise Vincent 		      BITS_WITH_WMASK(1, 0x3U, 14));
631010d6ae3SXiaoDong Huang }
632010d6ae3SXiaoDong Huang 
633010d6ae3SXiaoDong Huang static void pvtm_32k_config_restore(void)
634010d6ae3SXiaoDong Huang {
635010d6ae3SXiaoDong Huang 	mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0),
6368a079e88SAmbroise Vincent 		      ddr_data.pmu_cru_clksel_con0 | BITS_WMSK(0x3U, 14));
637010d6ae3SXiaoDong Huang 
638010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
639010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pgrf_pvtm_con[0]));
640010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1,
641010d6ae3SXiaoDong Huang 		      ddr_data.pgrf_pvtm_con[1]);
642010d6ae3SXiaoDong Huang }
643010d6ae3SXiaoDong Huang 
644010d6ae3SXiaoDong Huang static void ddr_sleep_config(void)
645010d6ae3SXiaoDong Huang {
646010d6ae3SXiaoDong Huang 	/* disable ddr pd, sr */
647010d6ae3SXiaoDong Huang 	ddr_data.ddrc_pwrctrl = mmio_read_32(DDR_UPCTL_BASE + 0x30);
648010d6ae3SXiaoDong Huang 	mmio_write_32(DDR_UPCTL_BASE + 0x30, BITS_WITH_WMASK(0x0, 0x3, 0));
649010d6ae3SXiaoDong Huang 
650010d6ae3SXiaoDong Huang 	/* disable ddr auto gt */
651010d6ae3SXiaoDong Huang 	ddr_data.ddrgrf_con1 = mmio_read_32(DDRGRF_BASE + 0x4);
652010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x4, BITS_WITH_WMASK(0x0, 0x1f, 0));
653010d6ae3SXiaoDong Huang 
654010d6ae3SXiaoDong Huang 	/* disable ddr standby */
655010d6ae3SXiaoDong Huang 	ddr_data.ddrstdby_con0 = mmio_read_32(DDR_STDBY_BASE + 0x0);
656010d6ae3SXiaoDong Huang 	mmio_write_32(DDR_STDBY_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 0));
657010d6ae3SXiaoDong Huang 	while ((mmio_read_32(DDR_UPCTL_BASE + 0x4) & 0x7) != 1)
658010d6ae3SXiaoDong Huang 		;
659010d6ae3SXiaoDong Huang 
660010d6ae3SXiaoDong Huang 	/* ddr pmu ctrl */
661010d6ae3SXiaoDong Huang 	ddr_data.ddrgrf_con0 = mmio_read_32(DDRGRF_BASE + 0x0);
662010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 5));
663010d6ae3SXiaoDong Huang 	dsb();
664010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x1, 0x1, 4));
665010d6ae3SXiaoDong Huang 
666010d6ae3SXiaoDong Huang 	/* ddr ret sel */
667010d6ae3SXiaoDong Huang 	ddr_data.pmugrf_soc_con0 =
668010d6ae3SXiaoDong Huang 		mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(0));
669010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0),
670010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(0x0, 0x1, 12));
671010d6ae3SXiaoDong Huang }
672010d6ae3SXiaoDong Huang 
673010d6ae3SXiaoDong Huang static void ddr_sleep_config_restore(void)
674010d6ae3SXiaoDong Huang {
675010d6ae3SXiaoDong Huang 	/* restore ddr ret sel */
676010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0),
677010d6ae3SXiaoDong Huang 		      ddr_data.pmugrf_soc_con0 | BITS_WMSK(0x1, 12));
678010d6ae3SXiaoDong Huang 
679010d6ae3SXiaoDong Huang 	/* restore ddr pmu ctrl */
680010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x0,
681010d6ae3SXiaoDong Huang 		      ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 4));
682010d6ae3SXiaoDong Huang 	dsb();
683010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x0,
684010d6ae3SXiaoDong Huang 		      ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 5));
685010d6ae3SXiaoDong Huang 
686010d6ae3SXiaoDong Huang 	/* restore ddr standby */
687010d6ae3SXiaoDong Huang 	mmio_write_32(DDR_STDBY_BASE + 0x0,
688010d6ae3SXiaoDong Huang 		      ddr_data.ddrstdby_con0 | BITS_WMSK(0x1, 0));
689010d6ae3SXiaoDong Huang 
690010d6ae3SXiaoDong Huang 	/* restore ddr auto gt */
691010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x4,
692010d6ae3SXiaoDong Huang 		      ddr_data.ddrgrf_con1 | BITS_WMSK(0x1f, 0));
693010d6ae3SXiaoDong Huang 
694010d6ae3SXiaoDong Huang 	/* restore ddr pd, sr */
695010d6ae3SXiaoDong Huang 	mmio_write_32(DDR_UPCTL_BASE + 0x30,
696010d6ae3SXiaoDong Huang 		      ddr_data.ddrc_pwrctrl | BITS_WMSK(0x3, 0));
697010d6ae3SXiaoDong Huang }
698010d6ae3SXiaoDong Huang 
699010d6ae3SXiaoDong Huang static void pmu_sleep_config(void)
700010d6ae3SXiaoDong Huang {
701010d6ae3SXiaoDong Huang 	uint32_t pwrmd_core_lo, pwrmd_core_hi, pwrmd_com_lo, pwrmd_com_hi;
702010d6ae3SXiaoDong Huang 	uint32_t pmu_wkup_cfg2_lo;
703010d6ae3SXiaoDong Huang 	uint32_t clk_freq_khz;
704010d6ae3SXiaoDong Huang 
705010d6ae3SXiaoDong Huang 	/* save pmic_sleep iomux gpio0_a4 */
706010d6ae3SXiaoDong Huang 	ddr_data.pmic_slp_iomux = mmio_read_32(PMUGRF_BASE + GPIO0A_IOMUX);
707010d6ae3SXiaoDong Huang 
708010d6ae3SXiaoDong Huang 	ddr_data.pmu_pwrmd_core_l =
709010d6ae3SXiaoDong Huang 			mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_LO);
710010d6ae3SXiaoDong Huang 	ddr_data.pmu_pwrmd_core_h =
711010d6ae3SXiaoDong Huang 			mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_HI);
712010d6ae3SXiaoDong Huang 	ddr_data.pmu_pwrmd_cmm_l =
713010d6ae3SXiaoDong Huang 			mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO);
714010d6ae3SXiaoDong Huang 	ddr_data.pmu_pwrmd_cmm_h =
715010d6ae3SXiaoDong Huang 			mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI);
716010d6ae3SXiaoDong Huang 	ddr_data.pmu_wkup_cfg2_l = mmio_read_32(PMU_BASE + PMU_WKUP_CFG2_LO);
717010d6ae3SXiaoDong Huang 
718010d6ae3SXiaoDong Huang 	pwrmd_core_lo = BIT(pmu_global_int_dis) |
719010d6ae3SXiaoDong Huang 			BIT(pmu_core_src_gt) |
720010d6ae3SXiaoDong Huang 			BIT(pmu_cpu0_pd) |
721010d6ae3SXiaoDong Huang 			BIT(pmu_clr_core) |
722010d6ae3SXiaoDong Huang 			BIT(pmu_scu_pd) |
723010d6ae3SXiaoDong Huang 			BIT(pmu_l2_idle) |
724010d6ae3SXiaoDong Huang 			BIT(pmu_l2_flush) |
725010d6ae3SXiaoDong Huang 			BIT(pmu_clr_bus2main) |
726010d6ae3SXiaoDong Huang 			BIT(pmu_clr_peri2msch);
727010d6ae3SXiaoDong Huang 
728010d6ae3SXiaoDong Huang 	pwrmd_core_hi = BIT(pmu_dpll_pd_en) |
729010d6ae3SXiaoDong Huang 			BIT(pmu_apll_pd_en) |
730010d6ae3SXiaoDong Huang 			BIT(pmu_cpll_pd_en) |
731010d6ae3SXiaoDong Huang 			BIT(pmu_gpll_pd_en) |
732010d6ae3SXiaoDong Huang 			BIT(pmu_npll_pd_en);
733010d6ae3SXiaoDong Huang 
734010d6ae3SXiaoDong Huang 	pwrmd_com_lo = BIT(pmu_mode_en) |
735010d6ae3SXiaoDong Huang 		       BIT(pmu_pll_pd) |
736010d6ae3SXiaoDong Huang 		       BIT(pmu_pmu_use_if) |
737010d6ae3SXiaoDong Huang 		       BIT(pmu_alive_use_if) |
738010d6ae3SXiaoDong Huang 		       BIT(pmu_osc_dis) |
739010d6ae3SXiaoDong Huang 		       BIT(pmu_sref_enter) |
740010d6ae3SXiaoDong Huang 		       BIT(pmu_ddrc_gt) |
741010d6ae3SXiaoDong Huang 		       BIT(pmu_clr_pmu) |
742010d6ae3SXiaoDong Huang 		       BIT(pmu_clr_peri_pmu);
743010d6ae3SXiaoDong Huang 
744010d6ae3SXiaoDong Huang 	pwrmd_com_hi = BIT(pmu_clr_bus) |
745010d6ae3SXiaoDong Huang 		       BIT(pmu_clr_msch) |
746010d6ae3SXiaoDong Huang 		       BIT(pmu_wakeup_begin_cfg);
747010d6ae3SXiaoDong Huang 
748010d6ae3SXiaoDong Huang 	pmu_wkup_cfg2_lo = BIT(pmu_cluster_wkup_en) |
749010d6ae3SXiaoDong Huang 			   BIT(pmu_gpio_wkup_en) |
750010d6ae3SXiaoDong Huang 			   BIT(pmu_timer_wkup_en);
751010d6ae3SXiaoDong Huang 
752010d6ae3SXiaoDong Huang 	/* set pmic_sleep iomux gpio0_a4 */
753010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX,
754010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x3, 8));
755010d6ae3SXiaoDong Huang 
756010d6ae3SXiaoDong Huang 	clk_freq_khz = 32;
757010d6ae3SXiaoDong Huang 
758010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_OSC_CNT_LO,
759010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff));
760010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_OSC_CNT_HI,
761010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16));
762010d6ae3SXiaoDong Huang 
763010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_STABLE_CNT_LO,
764010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff));
765010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_STABLE_CNT_HI,
766010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16));
767010d6ae3SXiaoDong Huang 
768010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_LO,
769010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 2 & 0xffff));
770010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_HI,
771010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 2 >> 16));
772010d6ae3SXiaoDong Huang 
773010d6ae3SXiaoDong Huang 	/* Pmu's clk has switched to 24M back When pmu FSM counts
774010d6ae3SXiaoDong Huang 	 * the follow counters, so we should use 24M to calculate
775010d6ae3SXiaoDong Huang 	 * these counters.
776010d6ae3SXiaoDong Huang 	 */
777010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_LO,
778010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
779010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_HI,
780010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 >> 16));
781010d6ae3SXiaoDong Huang 
782010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_LO,
783010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
784010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_HI,
785010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 >> 16));
786010d6ae3SXiaoDong Huang 
787010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_LO,
788010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 5 & 0xffff));
789010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_HI,
790010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 5 >> 16));
791010d6ae3SXiaoDong Huang 
792010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_LO,
793010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
794010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_HI,
795010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 >> 16));
796010d6ae3SXiaoDong Huang 
797010d6ae3SXiaoDong Huang 	/* Config pmu power mode and pmu wakeup source */
798010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO,
799010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pwrmd_core_lo));
800010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI,
801010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pwrmd_core_hi));
802010d6ae3SXiaoDong Huang 
803010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO,
804010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pwrmd_com_lo));
805010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI,
806010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pwrmd_com_hi));
807010d6ae3SXiaoDong Huang 
808010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO,
809010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pmu_wkup_cfg2_lo));
810010d6ae3SXiaoDong Huang }
811010d6ae3SXiaoDong Huang 
812010d6ae3SXiaoDong Huang static void pmu_sleep_restore(void)
813010d6ae3SXiaoDong Huang {
814010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO,
815010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_l));
816010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI,
817010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_h));
818010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO,
819010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_l));
820010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI,
821010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_h));
822010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO,
823010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_wkup_cfg2_l));
824010d6ae3SXiaoDong Huang 
825010d6ae3SXiaoDong Huang 	/* restore pmic_sleep iomux */
826010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX,
827010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmic_slp_iomux));
828010d6ae3SXiaoDong Huang }
829010d6ae3SXiaoDong Huang 
830010d6ae3SXiaoDong Huang static void soc_sleep_config(void)
831010d6ae3SXiaoDong Huang {
832010d6ae3SXiaoDong Huang 	ddr_data.gpio0c_iomux = mmio_read_32(PMUGRF_BASE + GPIO0C_IOMUX);
833010d6ae3SXiaoDong Huang 
834010d6ae3SXiaoDong Huang 	pmu_sleep_config();
835010d6ae3SXiaoDong Huang 
836010d6ae3SXiaoDong Huang 	ddr_sleep_config();
837010d6ae3SXiaoDong Huang 
838010d6ae3SXiaoDong Huang 	pvtm_32k_config();
839010d6ae3SXiaoDong Huang }
840010d6ae3SXiaoDong Huang 
841010d6ae3SXiaoDong Huang static void soc_sleep_restore(void)
842010d6ae3SXiaoDong Huang {
843010d6ae3SXiaoDong Huang 	secure_timer_init();
844010d6ae3SXiaoDong Huang 
845010d6ae3SXiaoDong Huang 	pvtm_32k_config_restore();
846010d6ae3SXiaoDong Huang 
847010d6ae3SXiaoDong Huang 	ddr_sleep_config_restore();
848010d6ae3SXiaoDong Huang 
849010d6ae3SXiaoDong Huang 	pmu_sleep_restore();
850010d6ae3SXiaoDong Huang 
851010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + GPIO0C_IOMUX,
852010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.gpio0c_iomux));
853010d6ae3SXiaoDong Huang }
854010d6ae3SXiaoDong Huang 
855010d6ae3SXiaoDong Huang static inline void pm_pll_wait_lock(uint32_t pll_base, uint32_t pll_id)
856010d6ae3SXiaoDong Huang {
857010d6ae3SXiaoDong Huang 	uint32_t delay = PLL_LOCKED_TIMEOUT;
858010d6ae3SXiaoDong Huang 
859010d6ae3SXiaoDong Huang 	while (delay > 0) {
860010d6ae3SXiaoDong Huang 		if (mmio_read_32(pll_base + PLL_CON(1)) &
861010d6ae3SXiaoDong Huang 		    PLL_LOCK_MSK)
862010d6ae3SXiaoDong Huang 			break;
863010d6ae3SXiaoDong Huang 		delay--;
864010d6ae3SXiaoDong Huang 	}
865010d6ae3SXiaoDong Huang 
866010d6ae3SXiaoDong Huang 	if (delay == 0)
867010d6ae3SXiaoDong Huang 		ERROR("Can't wait pll:%d lock\n", pll_id);
868010d6ae3SXiaoDong Huang }
869010d6ae3SXiaoDong Huang 
870010d6ae3SXiaoDong Huang static inline void pll_pwr_ctr(uint32_t pll_base, uint32_t pll_id, uint32_t pd)
871010d6ae3SXiaoDong Huang {
872010d6ae3SXiaoDong Huang 	mmio_write_32(pll_base + PLL_CON(1),
8738a079e88SAmbroise Vincent 		      BITS_WITH_WMASK(1, 1U, 15));
874010d6ae3SXiaoDong Huang 	if (pd)
875010d6ae3SXiaoDong Huang 		mmio_write_32(pll_base + PLL_CON(1),
876010d6ae3SXiaoDong Huang 			      BITS_WITH_WMASK(1, 1, 14));
877010d6ae3SXiaoDong Huang 	else
878010d6ae3SXiaoDong Huang 		mmio_write_32(pll_base + PLL_CON(1),
879010d6ae3SXiaoDong Huang 			      BITS_WITH_WMASK(0, 1, 14));
880010d6ae3SXiaoDong Huang }
881010d6ae3SXiaoDong Huang 
882010d6ae3SXiaoDong Huang static inline void pll_set_mode(uint32_t pll_id, uint32_t mode)
883010d6ae3SXiaoDong Huang {
884010d6ae3SXiaoDong Huang 	uint32_t val = BITS_WITH_WMASK(mode, 0x3, PLL_MODE_SHIFT(pll_id));
885010d6ae3SXiaoDong Huang 
886010d6ae3SXiaoDong Huang 	if (pll_id != GPLL_ID)
887010d6ae3SXiaoDong Huang 		mmio_write_32(CRU_BASE + CRU_MODE, val);
888010d6ae3SXiaoDong Huang 	else
889010d6ae3SXiaoDong Huang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_MODE,
890010d6ae3SXiaoDong Huang 			      BITS_WITH_WMASK(mode, 0x3, 0));
891010d6ae3SXiaoDong Huang }
892010d6ae3SXiaoDong Huang 
893010d6ae3SXiaoDong Huang static inline void pll_suspend(uint32_t pll_id)
894010d6ae3SXiaoDong Huang {
895010d6ae3SXiaoDong Huang 	int i;
896010d6ae3SXiaoDong Huang 	uint32_t pll_base;
897010d6ae3SXiaoDong Huang 
898010d6ae3SXiaoDong Huang 	if (pll_id != GPLL_ID)
899010d6ae3SXiaoDong Huang 		pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0);
900010d6ae3SXiaoDong Huang 	else
901010d6ae3SXiaoDong Huang 		pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0);
902010d6ae3SXiaoDong Huang 
903010d6ae3SXiaoDong Huang 	/* save pll con */
904010d6ae3SXiaoDong Huang 	for (i = 0; i < PLL_CON_CNT; i++)
905010d6ae3SXiaoDong Huang 		ddr_data.cru_plls_con_save[pll_id][i] =
906010d6ae3SXiaoDong Huang 				mmio_read_32(pll_base + PLL_CON(i));
907010d6ae3SXiaoDong Huang 
908010d6ae3SXiaoDong Huang 	/* slow mode */
909010d6ae3SXiaoDong Huang 	pll_set_mode(pll_id, SLOW_MODE);
910010d6ae3SXiaoDong Huang }
911010d6ae3SXiaoDong Huang 
912010d6ae3SXiaoDong Huang static inline void pll_resume(uint32_t pll_id)
913010d6ae3SXiaoDong Huang {
914010d6ae3SXiaoDong Huang 	uint32_t mode, pll_base;
915010d6ae3SXiaoDong Huang 
916010d6ae3SXiaoDong Huang 	if (pll_id != GPLL_ID) {
917010d6ae3SXiaoDong Huang 		pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0);
918010d6ae3SXiaoDong Huang 		mode = (ddr_data.cru_mode_save >> PLL_MODE_SHIFT(pll_id)) & 0x3;
919010d6ae3SXiaoDong Huang 	} else {
920010d6ae3SXiaoDong Huang 		pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0);
921010d6ae3SXiaoDong Huang 		mode = ddr_data.cru_pmu_mode_save & 0x3;
922010d6ae3SXiaoDong Huang 	}
923010d6ae3SXiaoDong Huang 
924010d6ae3SXiaoDong Huang 	/* if pll locked before suspend, we should wait atfer resume */
925010d6ae3SXiaoDong Huang 	if (ddr_data.cru_plls_con_save[pll_id][1] & PLL_LOCK_MSK)
926010d6ae3SXiaoDong Huang 		pm_pll_wait_lock(pll_base, pll_id);
927010d6ae3SXiaoDong Huang 
928010d6ae3SXiaoDong Huang 	pll_set_mode(pll_id, mode);
929010d6ae3SXiaoDong Huang }
930010d6ae3SXiaoDong Huang 
931010d6ae3SXiaoDong Huang static void pm_plls_suspend(void)
932010d6ae3SXiaoDong Huang {
933010d6ae3SXiaoDong Huang 	ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_MODE);
934010d6ae3SXiaoDong Huang 	ddr_data.cru_pmu_mode_save = mmio_read_32(PMUCRU_BASE + CRU_PMU_MODE);
935010d6ae3SXiaoDong Huang 	ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(0));
936010d6ae3SXiaoDong Huang 
937010d6ae3SXiaoDong Huang 	pll_suspend(GPLL_ID);
938010d6ae3SXiaoDong Huang 	pll_suspend(NPLL_ID);
939010d6ae3SXiaoDong Huang 	pll_suspend(CPLL_ID);
940010d6ae3SXiaoDong Huang 	pll_suspend(APLL_ID);
941010d6ae3SXiaoDong Huang 
942010d6ae3SXiaoDong Huang 	/* core */
943010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
944010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 0));
945010d6ae3SXiaoDong Huang 
946010d6ae3SXiaoDong Huang 	/* pclk_dbg */
947010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
948010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 8));
949010d6ae3SXiaoDong Huang }
950010d6ae3SXiaoDong Huang 
951010d6ae3SXiaoDong Huang static void pm_plls_resume(void)
952010d6ae3SXiaoDong Huang {
953010d6ae3SXiaoDong Huang 	/* pclk_dbg */
954010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
955010d6ae3SXiaoDong Huang 		      ddr_data.clk_sel0 | BITS_WMSK(0xf, 8));
956010d6ae3SXiaoDong Huang 
957010d6ae3SXiaoDong Huang 	/* core */
958010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
959010d6ae3SXiaoDong Huang 		      ddr_data.clk_sel0 | BITS_WMSK(0xf, 0));
960010d6ae3SXiaoDong Huang 
961010d6ae3SXiaoDong Huang 	pll_resume(APLL_ID);
962010d6ae3SXiaoDong Huang 	pll_resume(CPLL_ID);
963010d6ae3SXiaoDong Huang 	pll_resume(NPLL_ID);
964010d6ae3SXiaoDong Huang 	pll_resume(GPLL_ID);
965010d6ae3SXiaoDong Huang }
966010d6ae3SXiaoDong Huang 
967010d6ae3SXiaoDong Huang int rockchip_soc_sys_pwr_dm_suspend(void)
968010d6ae3SXiaoDong Huang {
969010d6ae3SXiaoDong Huang 	pmu_power_domains_suspend();
970010d6ae3SXiaoDong Huang 
971010d6ae3SXiaoDong Huang 	clk_gate_suspend();
972010d6ae3SXiaoDong Huang 
973010d6ae3SXiaoDong Huang 	soc_sleep_config();
974010d6ae3SXiaoDong Huang 
975010d6ae3SXiaoDong Huang 	pm_plls_suspend();
976010d6ae3SXiaoDong Huang 
977010d6ae3SXiaoDong Huang 	psram_boot_cfg->pm_flag &= ~PM_WARM_BOOT_BIT;
978010d6ae3SXiaoDong Huang 
979010d6ae3SXiaoDong Huang 	return 0;
980010d6ae3SXiaoDong Huang }
981010d6ae3SXiaoDong Huang 
982010d6ae3SXiaoDong Huang int rockchip_soc_sys_pwr_dm_resume(void)
983010d6ae3SXiaoDong Huang {
984010d6ae3SXiaoDong Huang 	psram_boot_cfg->pm_flag |= PM_WARM_BOOT_BIT;
985010d6ae3SXiaoDong Huang 
986010d6ae3SXiaoDong Huang 	pm_plls_resume();
987010d6ae3SXiaoDong Huang 
988010d6ae3SXiaoDong Huang 	soc_sleep_restore();
989010d6ae3SXiaoDong Huang 
990010d6ae3SXiaoDong Huang 	clk_gate_resume();
991010d6ae3SXiaoDong Huang 
992010d6ae3SXiaoDong Huang 	pmu_power_domains_resume();
993010d6ae3SXiaoDong Huang 
994010d6ae3SXiaoDong Huang 	plat_rockchip_gic_cpuif_enable();
995010d6ae3SXiaoDong Huang 
996010d6ae3SXiaoDong Huang 	return 0;
997010d6ae3SXiaoDong Huang }
998010d6ae3SXiaoDong Huang 
999010d6ae3SXiaoDong Huang void __dead2 rockchip_soc_soft_reset(void)
1000010d6ae3SXiaoDong Huang {
1001010d6ae3SXiaoDong Huang 	pll_set_mode(GPLL_ID, SLOW_MODE);
1002010d6ae3SXiaoDong Huang 	pll_set_mode(CPLL_ID, SLOW_MODE);
1003010d6ae3SXiaoDong Huang 	pll_set_mode(NPLL_ID, SLOW_MODE);
1004010d6ae3SXiaoDong Huang 	pll_set_mode(APLL_ID, SLOW_MODE);
1005010d6ae3SXiaoDong Huang 	dsb();
1006010d6ae3SXiaoDong Huang 
1007010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE);
1008010d6ae3SXiaoDong Huang 	dsb();
1009010d6ae3SXiaoDong Huang 
1010010d6ae3SXiaoDong Huang 	/*
1011010d6ae3SXiaoDong Huang 	 * Maybe the HW needs some times to reset the system,
1012010d6ae3SXiaoDong Huang 	 * so we do not hope the core to execute valid codes.
1013010d6ae3SXiaoDong Huang 	 */
1014010d6ae3SXiaoDong Huang 	psci_power_down_wfi();
1015010d6ae3SXiaoDong Huang }
1016010d6ae3SXiaoDong Huang 
1017010d6ae3SXiaoDong Huang void __dead2 rockchip_soc_system_off(void)
1018010d6ae3SXiaoDong Huang {
1019010d6ae3SXiaoDong Huang 	uint32_t val;
1020010d6ae3SXiaoDong Huang 
1021010d6ae3SXiaoDong Huang 	/* set pmic_sleep pin(gpio0_a4) to gpio mode */
1022010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, BITS_WITH_WMASK(0, 0x3, 8));
1023010d6ae3SXiaoDong Huang 
1024010d6ae3SXiaoDong Huang 	/* config output */
1025010d6ae3SXiaoDong Huang 	val = mmio_read_32(GPIO0_BASE + SWPORTA_DDR);
1026010d6ae3SXiaoDong Huang 	val |= BIT(4);
1027010d6ae3SXiaoDong Huang 	mmio_write_32(GPIO0_BASE + SWPORTA_DDR, val);
1028010d6ae3SXiaoDong Huang 
1029010d6ae3SXiaoDong Huang 	/* config output high level */
1030010d6ae3SXiaoDong Huang 	val = mmio_read_32(GPIO0_BASE);
1031010d6ae3SXiaoDong Huang 	val |= BIT(4);
1032010d6ae3SXiaoDong Huang 	mmio_write_32(GPIO0_BASE, val);
1033010d6ae3SXiaoDong Huang 	dsb();
1034010d6ae3SXiaoDong Huang 
1035010d6ae3SXiaoDong Huang 	/*
1036010d6ae3SXiaoDong Huang 	 * Maybe the HW needs some times to reset the system,
1037010d6ae3SXiaoDong Huang 	 * so we do not hope the core to execute valid codes.
1038010d6ae3SXiaoDong Huang 	 */
1039010d6ae3SXiaoDong Huang 	psci_power_down_wfi();
1040010d6ae3SXiaoDong Huang }
1041010d6ae3SXiaoDong Huang 
1042010d6ae3SXiaoDong Huang void rockchip_plat_mmu_el3(void)
1043010d6ae3SXiaoDong Huang {
1044010d6ae3SXiaoDong Huang 	/* TODO: support the el3 for px30 SoCs */
1045010d6ae3SXiaoDong Huang }
1046010d6ae3SXiaoDong Huang 
1047010d6ae3SXiaoDong Huang void plat_rockchip_pmu_init(void)
1048010d6ae3SXiaoDong Huang {
1049010d6ae3SXiaoDong Huang 	uint32_t cpu;
1050010d6ae3SXiaoDong Huang 
1051010d6ae3SXiaoDong Huang 	rockchip_pd_lock_init();
1052010d6ae3SXiaoDong Huang 
1053010d6ae3SXiaoDong Huang 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
1054010d6ae3SXiaoDong Huang 		cpuson_flags[cpu] = 0;
1055010d6ae3SXiaoDong Huang 
1056010d6ae3SXiaoDong Huang 	psram_boot_cfg->ddr_func = (uint64_t)0;
1057010d6ae3SXiaoDong Huang 	psram_boot_cfg->ddr_data = (uint64_t)0;
1058010d6ae3SXiaoDong Huang 	psram_boot_cfg->sp = PSRAM_SP_TOP;
1059010d6ae3SXiaoDong Huang 	psram_boot_cfg->ddr_flag = 0x0;
1060010d6ae3SXiaoDong Huang 	psram_boot_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
1061010d6ae3SXiaoDong Huang 	psram_boot_cfg->pm_flag = PM_WARM_BOOT_BIT;
1062010d6ae3SXiaoDong Huang 
1063010d6ae3SXiaoDong Huang 	nonboot_cpus_off();
1064010d6ae3SXiaoDong Huang 
1065010d6ae3SXiaoDong Huang 	/* Remap pmu_sram's base address to boot address */
1066010d6ae3SXiaoDong Huang 	mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0),
1067010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, 13));
1068010d6ae3SXiaoDong Huang 
1069010d6ae3SXiaoDong Huang 	INFO("%s: pd status %x\n",
1070010d6ae3SXiaoDong Huang 	     __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
1071010d6ae3SXiaoDong Huang }
1072