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