xref: /rk3399_ARM-atf/plat/rockchip/px30/drivers/pmu/pmu.c (revision 010d6ae3388ef63f2a2afcd408c1dc461fb43583)
1*010d6ae3SXiaoDong Huang /*
2*010d6ae3SXiaoDong Huang  * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
3*010d6ae3SXiaoDong Huang  *
4*010d6ae3SXiaoDong Huang  * SPDX-License-Identifier: BSD-3-Clause
5*010d6ae3SXiaoDong Huang  */
6*010d6ae3SXiaoDong Huang 
7*010d6ae3SXiaoDong Huang #include <assert.h>
8*010d6ae3SXiaoDong Huang #include <errno.h>
9*010d6ae3SXiaoDong Huang 
10*010d6ae3SXiaoDong Huang #include <platform_def.h>
11*010d6ae3SXiaoDong Huang 
12*010d6ae3SXiaoDong Huang #include <arch_helpers.h>
13*010d6ae3SXiaoDong Huang #include <bl31/bl31.h>
14*010d6ae3SXiaoDong Huang #include <common/debug.h>
15*010d6ae3SXiaoDong Huang #include <drivers/console.h>
16*010d6ae3SXiaoDong Huang #include <drivers/delay_timer.h>
17*010d6ae3SXiaoDong Huang #include <lib/bakery_lock.h>
18*010d6ae3SXiaoDong Huang #include <lib/mmio.h>
19*010d6ae3SXiaoDong Huang #include <plat/common/platform.h>
20*010d6ae3SXiaoDong Huang 
21*010d6ae3SXiaoDong Huang #include <cpus_on_fixed_addr.h>
22*010d6ae3SXiaoDong Huang #include <plat_private.h>
23*010d6ae3SXiaoDong Huang #include <pmu.h>
24*010d6ae3SXiaoDong Huang #include <px30_def.h>
25*010d6ae3SXiaoDong Huang #include <soc.h>
26*010d6ae3SXiaoDong Huang 
27*010d6ae3SXiaoDong Huang DEFINE_BAKERY_LOCK(rockchip_pd_lock);
28*010d6ae3SXiaoDong Huang #define rockchip_pd_lock_init()	bakery_lock_init(&rockchip_pd_lock)
29*010d6ae3SXiaoDong Huang #define rockchip_pd_lock_get()	bakery_lock_get(&rockchip_pd_lock)
30*010d6ae3SXiaoDong Huang #define rockchip_pd_lock_rls()	bakery_lock_release(&rockchip_pd_lock)
31*010d6ae3SXiaoDong Huang 
32*010d6ae3SXiaoDong Huang static struct psram_data_t *psram_boot_cfg =
33*010d6ae3SXiaoDong Huang 	(struct psram_data_t *)&sys_sleep_flag_sram;
34*010d6ae3SXiaoDong Huang 
35*010d6ae3SXiaoDong Huang /*
36*010d6ae3SXiaoDong Huang  * There are two ways to powering on or off on core.
37*010d6ae3SXiaoDong Huang  * 1) Control it power domain into on or off in PMU_PWRDN_CON reg,
38*010d6ae3SXiaoDong Huang  *    it is core_pwr_pd mode
39*010d6ae3SXiaoDong Huang  * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
40*010d6ae3SXiaoDong Huang  *     then, if the core enter into wfi, it power domain will be
41*010d6ae3SXiaoDong Huang  *     powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode
42*010d6ae3SXiaoDong Huang  * so we need core_pm_cfg_info to distinguish which method be used now.
43*010d6ae3SXiaoDong Huang  */
44*010d6ae3SXiaoDong Huang 
45*010d6ae3SXiaoDong Huang static uint32_t cores_pd_cfg_info[PLATFORM_CORE_COUNT]
46*010d6ae3SXiaoDong Huang #if USE_COHERENT_MEM
47*010d6ae3SXiaoDong Huang __attribute__ ((section("tzfw_coherent_mem")))
48*010d6ae3SXiaoDong Huang #endif
49*010d6ae3SXiaoDong Huang ;
50*010d6ae3SXiaoDong Huang 
51*010d6ae3SXiaoDong Huang struct px30_sleep_ddr_data {
52*010d6ae3SXiaoDong Huang 	uint32_t clk_sel0;
53*010d6ae3SXiaoDong Huang 	uint32_t cru_mode_save;
54*010d6ae3SXiaoDong Huang 	uint32_t cru_pmu_mode_save;
55*010d6ae3SXiaoDong Huang 	uint32_t ddrc_hwlpctl;
56*010d6ae3SXiaoDong Huang 	uint32_t ddrc_pwrctrl;
57*010d6ae3SXiaoDong Huang 	uint32_t ddrgrf_con0;
58*010d6ae3SXiaoDong Huang 	uint32_t ddrgrf_con1;
59*010d6ae3SXiaoDong Huang 	uint32_t ddrstdby_con0;
60*010d6ae3SXiaoDong Huang 	uint32_t gpio0b_iomux;
61*010d6ae3SXiaoDong Huang 	uint32_t gpio0c_iomux;
62*010d6ae3SXiaoDong Huang 	uint32_t pmu_pwrmd_core_l;
63*010d6ae3SXiaoDong Huang 	uint32_t pmu_pwrmd_core_h;
64*010d6ae3SXiaoDong Huang 	uint32_t pmu_pwrmd_cmm_l;
65*010d6ae3SXiaoDong Huang 	uint32_t pmu_pwrmd_cmm_h;
66*010d6ae3SXiaoDong Huang 	uint32_t pmu_wkup_cfg2_l;
67*010d6ae3SXiaoDong Huang 	uint32_t pmu_cru_clksel_con0;
68*010d6ae3SXiaoDong Huang 	uint32_t pmugrf_soc_con0;
69*010d6ae3SXiaoDong Huang 	uint32_t pmusgrf_soc_con0;
70*010d6ae3SXiaoDong Huang 	uint32_t pmic_slp_iomux;
71*010d6ae3SXiaoDong Huang 	uint32_t pgrf_pvtm_con[2];
72*010d6ae3SXiaoDong Huang 	uint32_t cru_clk_gate[CRU_CLKGATES_CON_CNT];
73*010d6ae3SXiaoDong Huang 	uint32_t cru_pmu_clk_gate[CRU_PMU_CLKGATE_CON_CNT];
74*010d6ae3SXiaoDong Huang 	uint32_t cru_plls_con_save[END_PLL_ID][PLL_CON_CNT];
75*010d6ae3SXiaoDong Huang 	uint32_t cpu_qos[CPU_AXI_QOS_NUM_REGS];
76*010d6ae3SXiaoDong Huang 	uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS];
77*010d6ae3SXiaoDong Huang 	uint32_t isp_128m_qos[CPU_AXI_QOS_NUM_REGS];
78*010d6ae3SXiaoDong Huang 	uint32_t isp_rd_qos[CPU_AXI_QOS_NUM_REGS];
79*010d6ae3SXiaoDong Huang 	uint32_t isp_wr_qos[CPU_AXI_QOS_NUM_REGS];
80*010d6ae3SXiaoDong Huang 	uint32_t isp_m1_qos[CPU_AXI_QOS_NUM_REGS];
81*010d6ae3SXiaoDong Huang 	uint32_t vip_qos[CPU_AXI_QOS_NUM_REGS];
82*010d6ae3SXiaoDong Huang 	uint32_t rga_rd_qos[CPU_AXI_QOS_NUM_REGS];
83*010d6ae3SXiaoDong Huang 	uint32_t rga_wr_qos[CPU_AXI_QOS_NUM_REGS];
84*010d6ae3SXiaoDong Huang 	uint32_t vop_m0_qos[CPU_AXI_QOS_NUM_REGS];
85*010d6ae3SXiaoDong Huang 	uint32_t vop_m1_qos[CPU_AXI_QOS_NUM_REGS];
86*010d6ae3SXiaoDong Huang 	uint32_t vpu_qos[CPU_AXI_QOS_NUM_REGS];
87*010d6ae3SXiaoDong Huang 	uint32_t vpu_r128_qos[CPU_AXI_QOS_NUM_REGS];
88*010d6ae3SXiaoDong Huang 	uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS];
89*010d6ae3SXiaoDong Huang 	uint32_t dmac_qos[CPU_AXI_QOS_NUM_REGS];
90*010d6ae3SXiaoDong Huang 	uint32_t crypto_qos[CPU_AXI_QOS_NUM_REGS];
91*010d6ae3SXiaoDong Huang 	uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS];
92*010d6ae3SXiaoDong Huang 	uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS];
93*010d6ae3SXiaoDong Huang 	uint32_t nand_qos[CPU_AXI_QOS_NUM_REGS];
94*010d6ae3SXiaoDong Huang 	uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS];
95*010d6ae3SXiaoDong Huang 	uint32_t sfc_qos[CPU_AXI_QOS_NUM_REGS];
96*010d6ae3SXiaoDong Huang 	uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS];
97*010d6ae3SXiaoDong Huang 	uint32_t usb_host_qos[CPU_AXI_QOS_NUM_REGS];
98*010d6ae3SXiaoDong Huang 	uint32_t usb_otg_qos[CPU_AXI_QOS_NUM_REGS];
99*010d6ae3SXiaoDong Huang };
100*010d6ae3SXiaoDong Huang 
101*010d6ae3SXiaoDong Huang static struct px30_sleep_ddr_data ddr_data
102*010d6ae3SXiaoDong Huang #if USE_COHERENT_MEM
103*010d6ae3SXiaoDong Huang __attribute__ ((section("tzfw_coherent_mem")))
104*010d6ae3SXiaoDong Huang #endif
105*010d6ae3SXiaoDong Huang ;
106*010d6ae3SXiaoDong Huang 
107*010d6ae3SXiaoDong Huang static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
108*010d6ae3SXiaoDong Huang {
109*010d6ae3SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
110*010d6ae3SXiaoDong Huang 	return cores_pd_cfg_info[cpu_id];
111*010d6ae3SXiaoDong Huang }
112*010d6ae3SXiaoDong Huang 
113*010d6ae3SXiaoDong Huang static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
114*010d6ae3SXiaoDong Huang {
115*010d6ae3SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
116*010d6ae3SXiaoDong Huang 	cores_pd_cfg_info[cpu_id] = value;
117*010d6ae3SXiaoDong Huang #if !USE_COHERENT_MEM
118*010d6ae3SXiaoDong Huang 	flush_dcache_range((uintptr_t)&cores_pd_cfg_info[cpu_id],
119*010d6ae3SXiaoDong Huang 			   sizeof(uint32_t));
120*010d6ae3SXiaoDong Huang #endif
121*010d6ae3SXiaoDong Huang }
122*010d6ae3SXiaoDong Huang 
123*010d6ae3SXiaoDong Huang static inline uint32_t pmu_power_domain_st(uint32_t pd)
124*010d6ae3SXiaoDong Huang {
125*010d6ae3SXiaoDong Huang 	return mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd) ?
126*010d6ae3SXiaoDong Huang 	       pmu_pd_off :
127*010d6ae3SXiaoDong Huang 	       pmu_pd_on;
128*010d6ae3SXiaoDong Huang }
129*010d6ae3SXiaoDong Huang 
130*010d6ae3SXiaoDong Huang static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
131*010d6ae3SXiaoDong Huang {
132*010d6ae3SXiaoDong Huang 	uint32_t loop = 0;
133*010d6ae3SXiaoDong Huang 	int ret = 0;
134*010d6ae3SXiaoDong Huang 
135*010d6ae3SXiaoDong Huang 	rockchip_pd_lock_get();
136*010d6ae3SXiaoDong Huang 
137*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRDN_CON,
138*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(pd_state, 0x1, pd));
139*010d6ae3SXiaoDong Huang 	dsb();
140*010d6ae3SXiaoDong Huang 
141*010d6ae3SXiaoDong Huang 	while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
142*010d6ae3SXiaoDong Huang 		udelay(1);
143*010d6ae3SXiaoDong Huang 		loop++;
144*010d6ae3SXiaoDong Huang 	}
145*010d6ae3SXiaoDong Huang 
146*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(pd) != pd_state) {
147*010d6ae3SXiaoDong Huang 		WARN("%s: %d, %d, error!\n", __func__, pd, pd_state);
148*010d6ae3SXiaoDong Huang 		ret = -EINVAL;
149*010d6ae3SXiaoDong Huang 	}
150*010d6ae3SXiaoDong Huang 
151*010d6ae3SXiaoDong Huang 	rockchip_pd_lock_rls();
152*010d6ae3SXiaoDong Huang 
153*010d6ae3SXiaoDong Huang 	return ret;
154*010d6ae3SXiaoDong Huang }
155*010d6ae3SXiaoDong Huang 
156*010d6ae3SXiaoDong Huang static inline uint32_t pmu_bus_idle_st(uint32_t bus)
157*010d6ae3SXiaoDong Huang {
158*010d6ae3SXiaoDong Huang 	return !!((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus)) &&
159*010d6ae3SXiaoDong Huang 		  (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus + 16)));
160*010d6ae3SXiaoDong Huang }
161*010d6ae3SXiaoDong Huang 
162*010d6ae3SXiaoDong Huang static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
163*010d6ae3SXiaoDong Huang {
164*010d6ae3SXiaoDong Huang 	uint32_t wait_cnt = 0;
165*010d6ae3SXiaoDong Huang 
166*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_BUS_IDLE_REQ,
167*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(state, 0x1, bus));
168*010d6ae3SXiaoDong Huang 
169*010d6ae3SXiaoDong Huang 	while (pmu_bus_idle_st(bus) != state &&
170*010d6ae3SXiaoDong Huang 	       wait_cnt < BUS_IDLE_LOOP) {
171*010d6ae3SXiaoDong Huang 		udelay(1);
172*010d6ae3SXiaoDong Huang 		wait_cnt++;
173*010d6ae3SXiaoDong Huang 	}
174*010d6ae3SXiaoDong Huang 
175*010d6ae3SXiaoDong Huang 	if (pmu_bus_idle_st(bus) != state)
176*010d6ae3SXiaoDong Huang 		WARN("%s:idle_st=0x%x, bus_id=%d\n",
177*010d6ae3SXiaoDong Huang 		     __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST), bus);
178*010d6ae3SXiaoDong Huang }
179*010d6ae3SXiaoDong Huang 
180*010d6ae3SXiaoDong Huang static void qos_save(void)
181*010d6ae3SXiaoDong Huang {
182*010d6ae3SXiaoDong Huang 	/* scu powerdomain will power off, so cpu qos should be saved */
183*010d6ae3SXiaoDong Huang 	SAVE_QOS(ddr_data.cpu_qos, CPU);
184*010d6ae3SXiaoDong Huang 
185*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
186*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.gpu_qos, GPU);
187*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VI) == pmu_pd_on) {
188*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.isp_128m_qos, ISP_128M);
189*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.isp_rd_qos, ISP_RD);
190*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.isp_wr_qos, ISP_WR);
191*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.isp_m1_qos, ISP_M1);
192*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vip_qos, VIP);
193*010d6ae3SXiaoDong Huang 	}
194*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
195*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.rga_rd_qos, RGA_RD);
196*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.rga_wr_qos, RGA_WR);
197*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vop_m0_qos, VOP_M0);
198*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vop_m1_qos, VOP_M1);
199*010d6ae3SXiaoDong Huang 	}
200*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) {
201*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vpu_qos, VPU);
202*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.vpu_r128_qos, VPU_R128);
203*010d6ae3SXiaoDong Huang 	}
204*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) {
205*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.emmc_qos, EMMC);
206*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.nand_qos, NAND);
207*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.sdio_qos, SDIO);
208*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.sfc_qos, SFC);
209*010d6ae3SXiaoDong Huang 	}
210*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
211*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.gmac_qos, GMAC);
212*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on)
213*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.crypto_qos, CRYPTO);
214*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on)
215*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.sdmmc_qos, SDMMC);
216*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_USB) == pmu_pd_on) {
217*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.usb_host_qos, USB_HOST);
218*010d6ae3SXiaoDong Huang 		SAVE_QOS(ddr_data.usb_otg_qos, USB_OTG);
219*010d6ae3SXiaoDong Huang 	}
220*010d6ae3SXiaoDong Huang }
221*010d6ae3SXiaoDong Huang 
222*010d6ae3SXiaoDong Huang static void qos_restore(void)
223*010d6ae3SXiaoDong Huang {
224*010d6ae3SXiaoDong Huang 	RESTORE_QOS(ddr_data.cpu_qos, CPU);
225*010d6ae3SXiaoDong Huang 
226*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
227*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.gpu_qos, GPU);
228*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VI) == pmu_pd_on) {
229*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.isp_128m_qos, ISP_128M);
230*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.isp_rd_qos, ISP_RD);
231*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.isp_wr_qos, ISP_WR);
232*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.isp_m1_qos, ISP_M1);
233*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vip_qos, VIP);
234*010d6ae3SXiaoDong Huang 	}
235*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
236*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.rga_rd_qos, RGA_RD);
237*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.rga_wr_qos, RGA_WR);
238*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vop_m0_qos, VOP_M0);
239*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vop_m1_qos, VOP_M1);
240*010d6ae3SXiaoDong Huang 	}
241*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) {
242*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vpu_qos, VPU);
243*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.vpu_r128_qos, VPU_R128);
244*010d6ae3SXiaoDong Huang 	}
245*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) {
246*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.emmc_qos, EMMC);
247*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.nand_qos, NAND);
248*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.sdio_qos, SDIO);
249*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.sfc_qos, SFC);
250*010d6ae3SXiaoDong Huang 	}
251*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
252*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.gmac_qos, GMAC);
253*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on)
254*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.crypto_qos, CRYPTO);
255*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on)
256*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.sdmmc_qos, SDMMC);
257*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(PD_USB) == pmu_pd_on) {
258*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.usb_host_qos, USB_HOST);
259*010d6ae3SXiaoDong Huang 		RESTORE_QOS(ddr_data.usb_otg_qos, USB_OTG);
260*010d6ae3SXiaoDong Huang 	}
261*010d6ae3SXiaoDong Huang }
262*010d6ae3SXiaoDong Huang 
263*010d6ae3SXiaoDong Huang static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
264*010d6ae3SXiaoDong Huang {
265*010d6ae3SXiaoDong Huang 	uint32_t state;
266*010d6ae3SXiaoDong Huang 
267*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(pd_id) == pd_state)
268*010d6ae3SXiaoDong Huang 		goto out;
269*010d6ae3SXiaoDong Huang 
270*010d6ae3SXiaoDong Huang 	if (pd_state == pmu_pd_on)
271*010d6ae3SXiaoDong Huang 		pmu_power_domain_ctr(pd_id, pd_state);
272*010d6ae3SXiaoDong Huang 
273*010d6ae3SXiaoDong Huang 	state = (pd_state == pmu_pd_off) ? bus_idle : bus_active;
274*010d6ae3SXiaoDong Huang 
275*010d6ae3SXiaoDong Huang 	switch (pd_id) {
276*010d6ae3SXiaoDong Huang 	case PD_GPU:
277*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_GPU, state);
278*010d6ae3SXiaoDong Huang 		break;
279*010d6ae3SXiaoDong Huang 	case PD_VI:
280*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_VI, state);
281*010d6ae3SXiaoDong Huang 		break;
282*010d6ae3SXiaoDong Huang 	case PD_VO:
283*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_VO, state);
284*010d6ae3SXiaoDong Huang 		break;
285*010d6ae3SXiaoDong Huang 	case PD_VPU:
286*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_VPU, state);
287*010d6ae3SXiaoDong Huang 		break;
288*010d6ae3SXiaoDong Huang 	case PD_MMC_NAND:
289*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_MMC, state);
290*010d6ae3SXiaoDong Huang 		break;
291*010d6ae3SXiaoDong Huang 	case PD_GMAC:
292*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_GMAC, state);
293*010d6ae3SXiaoDong Huang 		break;
294*010d6ae3SXiaoDong Huang 	case PD_CRYPTO:
295*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_CRYPTO, state);
296*010d6ae3SXiaoDong Huang 		break;
297*010d6ae3SXiaoDong Huang 	case PD_SDCARD:
298*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_SDCARD, state);
299*010d6ae3SXiaoDong Huang 		break;
300*010d6ae3SXiaoDong Huang 	case PD_USB:
301*010d6ae3SXiaoDong Huang 		pmu_bus_idle_req(BUS_ID_USB, state);
302*010d6ae3SXiaoDong Huang 		break;
303*010d6ae3SXiaoDong Huang 	default:
304*010d6ae3SXiaoDong Huang 		break;
305*010d6ae3SXiaoDong Huang 	}
306*010d6ae3SXiaoDong Huang 
307*010d6ae3SXiaoDong Huang 	if (pd_state == pmu_pd_off)
308*010d6ae3SXiaoDong Huang 		pmu_power_domain_ctr(pd_id, pd_state);
309*010d6ae3SXiaoDong Huang 
310*010d6ae3SXiaoDong Huang out:
311*010d6ae3SXiaoDong Huang 	return 0;
312*010d6ae3SXiaoDong Huang }
313*010d6ae3SXiaoDong Huang 
314*010d6ae3SXiaoDong Huang static uint32_t pmu_powerdomain_state;
315*010d6ae3SXiaoDong Huang 
316*010d6ae3SXiaoDong Huang static void pmu_power_domains_suspend(void)
317*010d6ae3SXiaoDong Huang {
318*010d6ae3SXiaoDong Huang 	uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT];
319*010d6ae3SXiaoDong Huang 
320*010d6ae3SXiaoDong Huang 	clk_gate_con_save(clkgt_save);
321*010d6ae3SXiaoDong Huang 	clk_gate_con_disable();
322*010d6ae3SXiaoDong Huang 	qos_save();
323*010d6ae3SXiaoDong Huang 
324*010d6ae3SXiaoDong Huang 	pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
325*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_GPU, pmu_pd_off);
326*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_VI, pmu_pd_off);
327*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_VO, pmu_pd_off);
328*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_VPU, pmu_pd_off);
329*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_MMC_NAND, pmu_pd_off);
330*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_GMAC, pmu_pd_off);
331*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_CRYPTO, pmu_pd_off);
332*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_SDCARD, pmu_pd_off);
333*010d6ae3SXiaoDong Huang 	pmu_set_power_domain(PD_USB, pmu_pd_off);
334*010d6ae3SXiaoDong Huang 
335*010d6ae3SXiaoDong Huang 	clk_gate_con_restore(clkgt_save);
336*010d6ae3SXiaoDong Huang }
337*010d6ae3SXiaoDong Huang 
338*010d6ae3SXiaoDong Huang static void pmu_power_domains_resume(void)
339*010d6ae3SXiaoDong Huang {
340*010d6ae3SXiaoDong Huang 	uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT];
341*010d6ae3SXiaoDong Huang 
342*010d6ae3SXiaoDong Huang 	clk_gate_con_save(clkgt_save);
343*010d6ae3SXiaoDong Huang 	clk_gate_con_disable();
344*010d6ae3SXiaoDong Huang 
345*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_USB)))
346*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_USB, pmu_pd_on);
347*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_SDCARD)))
348*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_SDCARD, pmu_pd_on);
349*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_CRYPTO)))
350*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_CRYPTO, pmu_pd_on);
351*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_GMAC)))
352*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_GMAC, pmu_pd_on);
353*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_MMC_NAND)))
354*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_MMC_NAND, pmu_pd_on);
355*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_VPU)))
356*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_VPU, pmu_pd_on);
357*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_VO)))
358*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_VO, pmu_pd_on);
359*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_VI)))
360*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_VI, pmu_pd_on);
361*010d6ae3SXiaoDong Huang 	if (!(pmu_powerdomain_state & BIT(PD_GPU)))
362*010d6ae3SXiaoDong Huang 		pmu_set_power_domain(PD_GPU, pmu_pd_on);
363*010d6ae3SXiaoDong Huang 
364*010d6ae3SXiaoDong Huang 	qos_restore();
365*010d6ae3SXiaoDong Huang 	clk_gate_con_restore(clkgt_save);
366*010d6ae3SXiaoDong Huang }
367*010d6ae3SXiaoDong Huang 
368*010d6ae3SXiaoDong Huang static int check_cpu_wfie(uint32_t cpu)
369*010d6ae3SXiaoDong Huang {
370*010d6ae3SXiaoDong Huang 	uint32_t loop = 0, wfie_msk = CKECK_WFEI_MSK << cpu;
371*010d6ae3SXiaoDong Huang 
372*010d6ae3SXiaoDong Huang 	while (!(mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) &&
373*010d6ae3SXiaoDong Huang 	       (loop < WFEI_CHECK_LOOP)) {
374*010d6ae3SXiaoDong Huang 		udelay(1);
375*010d6ae3SXiaoDong Huang 		loop++;
376*010d6ae3SXiaoDong Huang 	}
377*010d6ae3SXiaoDong Huang 
378*010d6ae3SXiaoDong Huang 	if ((mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) == 0) {
379*010d6ae3SXiaoDong Huang 		WARN("%s: %d, %d, error!\n", __func__, cpu, wfie_msk);
380*010d6ae3SXiaoDong Huang 		return -EINVAL;
381*010d6ae3SXiaoDong Huang 	}
382*010d6ae3SXiaoDong Huang 
383*010d6ae3SXiaoDong Huang 	return 0;
384*010d6ae3SXiaoDong Huang }
385*010d6ae3SXiaoDong Huang 
386*010d6ae3SXiaoDong Huang static int cpus_power_domain_on(uint32_t cpu_id)
387*010d6ae3SXiaoDong Huang {
388*010d6ae3SXiaoDong Huang 	uint32_t cpu_pd, apm_value, cfg_info, loop = 0;
389*010d6ae3SXiaoDong Huang 
390*010d6ae3SXiaoDong Huang 	cpu_pd = PD_CPU0 + cpu_id;
391*010d6ae3SXiaoDong Huang 	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
392*010d6ae3SXiaoDong Huang 
393*010d6ae3SXiaoDong Huang 	if (cfg_info == core_pwr_pd) {
394*010d6ae3SXiaoDong Huang 		/* disable apm cfg */
395*010d6ae3SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
396*010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(CORES_PM_DISABLE));
397*010d6ae3SXiaoDong Huang 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
398*010d6ae3SXiaoDong Huang 			mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
399*010d6ae3SXiaoDong Huang 				      WITH_16BITS_WMSK(CORES_PM_DISABLE));
400*010d6ae3SXiaoDong Huang 			pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
401*010d6ae3SXiaoDong Huang 		}
402*010d6ae3SXiaoDong Huang 		pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
403*010d6ae3SXiaoDong Huang 	} else {
404*010d6ae3SXiaoDong Huang 		/* wait cpu down */
405*010d6ae3SXiaoDong Huang 		while (pmu_power_domain_st(cpu_pd) == pmu_pd_on && loop < 100) {
406*010d6ae3SXiaoDong Huang 			udelay(2);
407*010d6ae3SXiaoDong Huang 			loop++;
408*010d6ae3SXiaoDong Huang 		}
409*010d6ae3SXiaoDong Huang 
410*010d6ae3SXiaoDong Huang 		/* return error if can't wait cpu down */
411*010d6ae3SXiaoDong Huang 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
412*010d6ae3SXiaoDong Huang 			WARN("%s:can't wait cpu down\n", __func__);
413*010d6ae3SXiaoDong Huang 			return -EINVAL;
414*010d6ae3SXiaoDong Huang 		}
415*010d6ae3SXiaoDong Huang 
416*010d6ae3SXiaoDong Huang 		/* power up cpu in power down state */
417*010d6ae3SXiaoDong Huang 		apm_value = BIT(core_pm_sft_wakeup_en);
418*010d6ae3SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
419*010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(apm_value));
420*010d6ae3SXiaoDong Huang 	}
421*010d6ae3SXiaoDong Huang 
422*010d6ae3SXiaoDong Huang 	return 0;
423*010d6ae3SXiaoDong Huang }
424*010d6ae3SXiaoDong Huang 
425*010d6ae3SXiaoDong Huang static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
426*010d6ae3SXiaoDong Huang {
427*010d6ae3SXiaoDong Huang 	uint32_t cpu_pd, apm_value;
428*010d6ae3SXiaoDong Huang 
429*010d6ae3SXiaoDong Huang 	cpu_pd = PD_CPU0 + cpu_id;
430*010d6ae3SXiaoDong Huang 	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
431*010d6ae3SXiaoDong Huang 		return 0;
432*010d6ae3SXiaoDong Huang 
433*010d6ae3SXiaoDong Huang 	if (pd_cfg == core_pwr_pd) {
434*010d6ae3SXiaoDong Huang 		if (check_cpu_wfie(cpu_id))
435*010d6ae3SXiaoDong Huang 			return -EINVAL;
436*010d6ae3SXiaoDong Huang 		/* disable apm cfg */
437*010d6ae3SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
438*010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(CORES_PM_DISABLE));
439*010d6ae3SXiaoDong Huang 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
440*010d6ae3SXiaoDong Huang 		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
441*010d6ae3SXiaoDong Huang 	} else {
442*010d6ae3SXiaoDong Huang 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
443*010d6ae3SXiaoDong Huang 		apm_value = BIT(core_pm_en) | BIT(core_pm_dis_int);
444*010d6ae3SXiaoDong Huang 		if (pd_cfg == core_pwr_wfi_int)
445*010d6ae3SXiaoDong Huang 			apm_value |= BIT(core_pm_int_wakeup_en);
446*010d6ae3SXiaoDong Huang 		mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
447*010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(apm_value));
448*010d6ae3SXiaoDong Huang 	}
449*010d6ae3SXiaoDong Huang 
450*010d6ae3SXiaoDong Huang 	return 0;
451*010d6ae3SXiaoDong Huang }
452*010d6ae3SXiaoDong Huang 
453*010d6ae3SXiaoDong Huang static void nonboot_cpus_off(void)
454*010d6ae3SXiaoDong Huang {
455*010d6ae3SXiaoDong Huang 	uint32_t boot_cpu, cpu;
456*010d6ae3SXiaoDong Huang 
457*010d6ae3SXiaoDong Huang 	boot_cpu = plat_my_core_pos();
458*010d6ae3SXiaoDong Huang 
459*010d6ae3SXiaoDong Huang 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
460*010d6ae3SXiaoDong Huang 		if (cpu == boot_cpu)
461*010d6ae3SXiaoDong Huang 			continue;
462*010d6ae3SXiaoDong Huang 		cpus_power_domain_off(cpu, core_pwr_pd);
463*010d6ae3SXiaoDong Huang 	}
464*010d6ae3SXiaoDong Huang }
465*010d6ae3SXiaoDong Huang 
466*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr,
467*010d6ae3SXiaoDong Huang 				 uint64_t entrypoint)
468*010d6ae3SXiaoDong Huang {
469*010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
470*010d6ae3SXiaoDong Huang 
471*010d6ae3SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
472*010d6ae3SXiaoDong Huang 	assert(cpuson_flags[cpu_id] == 0);
473*010d6ae3SXiaoDong Huang 	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
474*010d6ae3SXiaoDong Huang 	cpuson_entry_point[cpu_id] = entrypoint;
475*010d6ae3SXiaoDong Huang 	dsb();
476*010d6ae3SXiaoDong Huang 
477*010d6ae3SXiaoDong Huang 	cpus_power_domain_on(cpu_id);
478*010d6ae3SXiaoDong Huang 
479*010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
480*010d6ae3SXiaoDong Huang }
481*010d6ae3SXiaoDong Huang 
482*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_on_finish(void)
483*010d6ae3SXiaoDong Huang {
484*010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
485*010d6ae3SXiaoDong Huang 
486*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
487*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(CORES_PM_DISABLE));
488*010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
489*010d6ae3SXiaoDong Huang }
490*010d6ae3SXiaoDong Huang 
491*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_off(void)
492*010d6ae3SXiaoDong Huang {
493*010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
494*010d6ae3SXiaoDong Huang 
495*010d6ae3SXiaoDong Huang 	cpus_power_domain_off(cpu_id, core_pwr_wfi);
496*010d6ae3SXiaoDong Huang 
497*010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
498*010d6ae3SXiaoDong Huang }
499*010d6ae3SXiaoDong Huang 
500*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_suspend(void)
501*010d6ae3SXiaoDong Huang {
502*010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
503*010d6ae3SXiaoDong Huang 
504*010d6ae3SXiaoDong Huang 	assert(cpu_id < PLATFORM_CORE_COUNT);
505*010d6ae3SXiaoDong Huang 	assert(cpuson_flags[cpu_id] == 0);
506*010d6ae3SXiaoDong Huang 	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
507*010d6ae3SXiaoDong Huang 	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
508*010d6ae3SXiaoDong Huang 	dsb();
509*010d6ae3SXiaoDong Huang 
510*010d6ae3SXiaoDong Huang 	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
511*010d6ae3SXiaoDong Huang 
512*010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
513*010d6ae3SXiaoDong Huang }
514*010d6ae3SXiaoDong Huang 
515*010d6ae3SXiaoDong Huang int rockchip_soc_cores_pwr_dm_resume(void)
516*010d6ae3SXiaoDong Huang {
517*010d6ae3SXiaoDong Huang 	uint32_t cpu_id = plat_my_core_pos();
518*010d6ae3SXiaoDong Huang 
519*010d6ae3SXiaoDong Huang 	/* Disable core_pm */
520*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id),
521*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(CORES_PM_DISABLE));
522*010d6ae3SXiaoDong Huang 
523*010d6ae3SXiaoDong Huang 	return PSCI_E_SUCCESS;
524*010d6ae3SXiaoDong Huang }
525*010d6ae3SXiaoDong Huang 
526*010d6ae3SXiaoDong Huang #define CLK_MSK_GATING(msk, con) \
527*010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + (con), ((msk) << 16) | 0xffff)
528*010d6ae3SXiaoDong Huang #define CLK_MSK_UNGATING(msk, con) \
529*010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + (con), ((~(msk)) << 16) | 0xffff)
530*010d6ae3SXiaoDong Huang 
531*010d6ae3SXiaoDong Huang static uint32_t clk_ungt_msk[CRU_CLKGATES_CON_CNT] = {
532*010d6ae3SXiaoDong Huang 	0xe0ff, 0xffff, 0x0000, 0x0000,
533*010d6ae3SXiaoDong Huang 	0x0000, 0x0380, 0x0000, 0x0000,
534*010d6ae3SXiaoDong Huang 	0x07c0, 0x0000, 0x0000, 0x000f,
535*010d6ae3SXiaoDong Huang 	0x0061, 0x1f02, 0x0440, 0x1801,
536*010d6ae3SXiaoDong Huang 	0x004b, 0x0000
537*010d6ae3SXiaoDong Huang };
538*010d6ae3SXiaoDong Huang 
539*010d6ae3SXiaoDong Huang static uint32_t clk_pmu_ungt_msk[CRU_PMU_CLKGATE_CON_CNT] = {
540*010d6ae3SXiaoDong Huang 	0xf1ff, 0x0310
541*010d6ae3SXiaoDong Huang };
542*010d6ae3SXiaoDong Huang 
543*010d6ae3SXiaoDong Huang void clk_gate_suspend(void)
544*010d6ae3SXiaoDong Huang {
545*010d6ae3SXiaoDong Huang 	int i;
546*010d6ae3SXiaoDong Huang 
547*010d6ae3SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) {
548*010d6ae3SXiaoDong Huang 		ddr_data.cru_clk_gate[i] =
549*010d6ae3SXiaoDong Huang 			mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i));
550*010d6ae3SXiaoDong Huang 			mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
551*010d6ae3SXiaoDong Huang 				      WITH_16BITS_WMSK(~clk_ungt_msk[i]));
552*010d6ae3SXiaoDong Huang 	}
553*010d6ae3SXiaoDong Huang 
554*010d6ae3SXiaoDong Huang 	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) {
555*010d6ae3SXiaoDong Huang 		ddr_data.cru_pmu_clk_gate[i] =
556*010d6ae3SXiaoDong Huang 			mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i));
557*010d6ae3SXiaoDong Huang 			mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
558*010d6ae3SXiaoDong Huang 				      WITH_16BITS_WMSK(~clk_pmu_ungt_msk[i]));
559*010d6ae3SXiaoDong Huang 	}
560*010d6ae3SXiaoDong Huang }
561*010d6ae3SXiaoDong Huang 
562*010d6ae3SXiaoDong Huang void clk_gate_resume(void)
563*010d6ae3SXiaoDong Huang {
564*010d6ae3SXiaoDong Huang 	int i;
565*010d6ae3SXiaoDong Huang 
566*010d6ae3SXiaoDong Huang 	for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++)
567*010d6ae3SXiaoDong Huang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i),
568*010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(ddr_data.cru_pmu_clk_gate[i]));
569*010d6ae3SXiaoDong Huang 
570*010d6ae3SXiaoDong Huang 	for (i = 0; i < CRU_CLKGATES_CON_CNT; i++)
571*010d6ae3SXiaoDong Huang 		mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i),
572*010d6ae3SXiaoDong Huang 			      WITH_16BITS_WMSK(ddr_data.cru_clk_gate[i]));
573*010d6ae3SXiaoDong Huang }
574*010d6ae3SXiaoDong Huang 
575*010d6ae3SXiaoDong Huang static void pvtm_32k_config(void)
576*010d6ae3SXiaoDong Huang {
577*010d6ae3SXiaoDong Huang 	uint32_t  pvtm_freq_khz, pvtm_div;
578*010d6ae3SXiaoDong Huang 
579*010d6ae3SXiaoDong Huang 	ddr_data.pmu_cru_clksel_con0 =
580*010d6ae3SXiaoDong Huang 		mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0));
581*010d6ae3SXiaoDong Huang 
582*010d6ae3SXiaoDong Huang 	ddr_data.pgrf_pvtm_con[0] =
583*010d6ae3SXiaoDong Huang 		mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON0);
584*010d6ae3SXiaoDong Huang 	ddr_data.pgrf_pvtm_con[1] =
585*010d6ae3SXiaoDong Huang 		mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON1);
586*010d6ae3SXiaoDong Huang 
587*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
588*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0x3, pgrf_pvtm_st));
589*010d6ae3SXiaoDong Huang 	dsb();
590*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
591*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_en));
592*010d6ae3SXiaoDong Huang 	dsb();
593*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, PVTM_CALC_CNT);
594*010d6ae3SXiaoDong Huang 	dsb();
595*010d6ae3SXiaoDong Huang 
596*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
597*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_st));
598*010d6ae3SXiaoDong Huang 
599*010d6ae3SXiaoDong Huang 	/* pmugrf_pvtm_st0 will be clear after PVTM start,
600*010d6ae3SXiaoDong Huang 	 * which will cost about 6 cycles of pvtm at least.
601*010d6ae3SXiaoDong Huang 	 * So we wait 30 cycles of pvtm for security.
602*010d6ae3SXiaoDong Huang 	 */
603*010d6ae3SXiaoDong Huang 	while (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) < 30)
604*010d6ae3SXiaoDong Huang 		;
605*010d6ae3SXiaoDong Huang 
606*010d6ae3SXiaoDong Huang 	dsb();
607*010d6ae3SXiaoDong Huang 	while (!(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST0) & 0x1))
608*010d6ae3SXiaoDong Huang 		;
609*010d6ae3SXiaoDong Huang 
610*010d6ae3SXiaoDong Huang 	pvtm_freq_khz =
611*010d6ae3SXiaoDong Huang 		(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) * 24000 +
612*010d6ae3SXiaoDong Huang 		PVTM_CALC_CNT / 2) / PVTM_CALC_CNT;
613*010d6ae3SXiaoDong Huang 	pvtm_div = (pvtm_freq_khz + 16) / 32;
614*010d6ae3SXiaoDong Huang 
615*010d6ae3SXiaoDong Huang 	/* pvtm_div = div_factor << 2 + 1,
616*010d6ae3SXiaoDong Huang 	 * so div_factor = (pvtm_div - 1) >> 2.
617*010d6ae3SXiaoDong Huang 	 * But the operation ">> 2" will clear the low bit of pvtm_div,
618*010d6ae3SXiaoDong Huang 	 * so we don't have to do "- 1" for compasation
619*010d6ae3SXiaoDong Huang 	 */
620*010d6ae3SXiaoDong Huang 	pvtm_div = pvtm_div >> 2;
621*010d6ae3SXiaoDong Huang 	if (pvtm_div > 0x3f)
622*010d6ae3SXiaoDong Huang 		pvtm_div = 0x3f;
623*010d6ae3SXiaoDong Huang 
624*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
625*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(pvtm_div, 0x3f, pgrf_pvtm_div));
626*010d6ae3SXiaoDong Huang 
627*010d6ae3SXiaoDong Huang 	/* select pvtm as 32k source */
628*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0),
629*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x3, 14));
630*010d6ae3SXiaoDong Huang }
631*010d6ae3SXiaoDong Huang 
632*010d6ae3SXiaoDong Huang static void pvtm_32k_config_restore(void)
633*010d6ae3SXiaoDong Huang {
634*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0),
635*010d6ae3SXiaoDong Huang 		      ddr_data.pmu_cru_clksel_con0 | BITS_WMSK(0x3, 14));
636*010d6ae3SXiaoDong Huang 
637*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0,
638*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pgrf_pvtm_con[0]));
639*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1,
640*010d6ae3SXiaoDong Huang 		      ddr_data.pgrf_pvtm_con[1]);
641*010d6ae3SXiaoDong Huang }
642*010d6ae3SXiaoDong Huang 
643*010d6ae3SXiaoDong Huang static void ddr_sleep_config(void)
644*010d6ae3SXiaoDong Huang {
645*010d6ae3SXiaoDong Huang 	/* disable ddr pd, sr */
646*010d6ae3SXiaoDong Huang 	ddr_data.ddrc_pwrctrl = mmio_read_32(DDR_UPCTL_BASE + 0x30);
647*010d6ae3SXiaoDong Huang 	mmio_write_32(DDR_UPCTL_BASE + 0x30, BITS_WITH_WMASK(0x0, 0x3, 0));
648*010d6ae3SXiaoDong Huang 
649*010d6ae3SXiaoDong Huang 	/* disable ddr auto gt */
650*010d6ae3SXiaoDong Huang 	ddr_data.ddrgrf_con1 = mmio_read_32(DDRGRF_BASE + 0x4);
651*010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x4, BITS_WITH_WMASK(0x0, 0x1f, 0));
652*010d6ae3SXiaoDong Huang 
653*010d6ae3SXiaoDong Huang 	/* disable ddr standby */
654*010d6ae3SXiaoDong Huang 	ddr_data.ddrstdby_con0 = mmio_read_32(DDR_STDBY_BASE + 0x0);
655*010d6ae3SXiaoDong Huang 	mmio_write_32(DDR_STDBY_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 0));
656*010d6ae3SXiaoDong Huang 	while ((mmio_read_32(DDR_UPCTL_BASE + 0x4) & 0x7) != 1)
657*010d6ae3SXiaoDong Huang 		;
658*010d6ae3SXiaoDong Huang 
659*010d6ae3SXiaoDong Huang 	/* ddr pmu ctrl */
660*010d6ae3SXiaoDong Huang 	ddr_data.ddrgrf_con0 = mmio_read_32(DDRGRF_BASE + 0x0);
661*010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 5));
662*010d6ae3SXiaoDong Huang 	dsb();
663*010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x1, 0x1, 4));
664*010d6ae3SXiaoDong Huang 
665*010d6ae3SXiaoDong Huang 	/* ddr ret sel */
666*010d6ae3SXiaoDong Huang 	ddr_data.pmugrf_soc_con0 =
667*010d6ae3SXiaoDong Huang 		mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(0));
668*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0),
669*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(0x0, 0x1, 12));
670*010d6ae3SXiaoDong Huang }
671*010d6ae3SXiaoDong Huang 
672*010d6ae3SXiaoDong Huang static void ddr_sleep_config_restore(void)
673*010d6ae3SXiaoDong Huang {
674*010d6ae3SXiaoDong Huang 	/* restore ddr ret sel */
675*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0),
676*010d6ae3SXiaoDong Huang 		      ddr_data.pmugrf_soc_con0 | BITS_WMSK(0x1, 12));
677*010d6ae3SXiaoDong Huang 
678*010d6ae3SXiaoDong Huang 	/* restore ddr pmu ctrl */
679*010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x0,
680*010d6ae3SXiaoDong Huang 		      ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 4));
681*010d6ae3SXiaoDong Huang 	dsb();
682*010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x0,
683*010d6ae3SXiaoDong Huang 		      ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 5));
684*010d6ae3SXiaoDong Huang 
685*010d6ae3SXiaoDong Huang 	/* restore ddr standby */
686*010d6ae3SXiaoDong Huang 	mmio_write_32(DDR_STDBY_BASE + 0x0,
687*010d6ae3SXiaoDong Huang 		      ddr_data.ddrstdby_con0 | BITS_WMSK(0x1, 0));
688*010d6ae3SXiaoDong Huang 
689*010d6ae3SXiaoDong Huang 	/* restore ddr auto gt */
690*010d6ae3SXiaoDong Huang 	mmio_write_32(DDRGRF_BASE + 0x4,
691*010d6ae3SXiaoDong Huang 		      ddr_data.ddrgrf_con1 | BITS_WMSK(0x1f, 0));
692*010d6ae3SXiaoDong Huang 
693*010d6ae3SXiaoDong Huang 	/* restore ddr pd, sr */
694*010d6ae3SXiaoDong Huang 	mmio_write_32(DDR_UPCTL_BASE + 0x30,
695*010d6ae3SXiaoDong Huang 		      ddr_data.ddrc_pwrctrl | BITS_WMSK(0x3, 0));
696*010d6ae3SXiaoDong Huang }
697*010d6ae3SXiaoDong Huang 
698*010d6ae3SXiaoDong Huang static void pmu_sleep_config(void)
699*010d6ae3SXiaoDong Huang {
700*010d6ae3SXiaoDong Huang 	uint32_t pwrmd_core_lo, pwrmd_core_hi, pwrmd_com_lo, pwrmd_com_hi;
701*010d6ae3SXiaoDong Huang 	uint32_t pmu_wkup_cfg2_lo;
702*010d6ae3SXiaoDong Huang 	uint32_t clk_freq_khz;
703*010d6ae3SXiaoDong Huang 
704*010d6ae3SXiaoDong Huang 	/* save pmic_sleep iomux gpio0_a4 */
705*010d6ae3SXiaoDong Huang 	ddr_data.pmic_slp_iomux = mmio_read_32(PMUGRF_BASE + GPIO0A_IOMUX);
706*010d6ae3SXiaoDong Huang 
707*010d6ae3SXiaoDong Huang 	ddr_data.pmu_pwrmd_core_l =
708*010d6ae3SXiaoDong Huang 			mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_LO);
709*010d6ae3SXiaoDong Huang 	ddr_data.pmu_pwrmd_core_h =
710*010d6ae3SXiaoDong Huang 			mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_HI);
711*010d6ae3SXiaoDong Huang 	ddr_data.pmu_pwrmd_cmm_l =
712*010d6ae3SXiaoDong Huang 			mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO);
713*010d6ae3SXiaoDong Huang 	ddr_data.pmu_pwrmd_cmm_h =
714*010d6ae3SXiaoDong Huang 			mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI);
715*010d6ae3SXiaoDong Huang 	ddr_data.pmu_wkup_cfg2_l = mmio_read_32(PMU_BASE + PMU_WKUP_CFG2_LO);
716*010d6ae3SXiaoDong Huang 
717*010d6ae3SXiaoDong Huang 	pwrmd_core_lo = BIT(pmu_global_int_dis) |
718*010d6ae3SXiaoDong Huang 			BIT(pmu_core_src_gt) |
719*010d6ae3SXiaoDong Huang 			BIT(pmu_cpu0_pd) |
720*010d6ae3SXiaoDong Huang 			BIT(pmu_clr_core) |
721*010d6ae3SXiaoDong Huang 			BIT(pmu_scu_pd) |
722*010d6ae3SXiaoDong Huang 			BIT(pmu_l2_idle) |
723*010d6ae3SXiaoDong Huang 			BIT(pmu_l2_flush) |
724*010d6ae3SXiaoDong Huang 			BIT(pmu_clr_bus2main) |
725*010d6ae3SXiaoDong Huang 			BIT(pmu_clr_peri2msch);
726*010d6ae3SXiaoDong Huang 
727*010d6ae3SXiaoDong Huang 	pwrmd_core_hi = BIT(pmu_dpll_pd_en) |
728*010d6ae3SXiaoDong Huang 			BIT(pmu_apll_pd_en) |
729*010d6ae3SXiaoDong Huang 			BIT(pmu_cpll_pd_en) |
730*010d6ae3SXiaoDong Huang 			BIT(pmu_gpll_pd_en) |
731*010d6ae3SXiaoDong Huang 			BIT(pmu_npll_pd_en);
732*010d6ae3SXiaoDong Huang 
733*010d6ae3SXiaoDong Huang 	pwrmd_com_lo = BIT(pmu_mode_en) |
734*010d6ae3SXiaoDong Huang 		       BIT(pmu_pll_pd) |
735*010d6ae3SXiaoDong Huang 		       BIT(pmu_pmu_use_if) |
736*010d6ae3SXiaoDong Huang 		       BIT(pmu_alive_use_if) |
737*010d6ae3SXiaoDong Huang 		       BIT(pmu_osc_dis) |
738*010d6ae3SXiaoDong Huang 		       BIT(pmu_sref_enter) |
739*010d6ae3SXiaoDong Huang 		       BIT(pmu_ddrc_gt) |
740*010d6ae3SXiaoDong Huang 		       BIT(pmu_clr_pmu) |
741*010d6ae3SXiaoDong Huang 		       BIT(pmu_clr_peri_pmu);
742*010d6ae3SXiaoDong Huang 
743*010d6ae3SXiaoDong Huang 	pwrmd_com_hi = BIT(pmu_clr_bus) |
744*010d6ae3SXiaoDong Huang 		       BIT(pmu_clr_msch) |
745*010d6ae3SXiaoDong Huang 		       BIT(pmu_wakeup_begin_cfg);
746*010d6ae3SXiaoDong Huang 
747*010d6ae3SXiaoDong Huang 	pmu_wkup_cfg2_lo = BIT(pmu_cluster_wkup_en) |
748*010d6ae3SXiaoDong Huang 			   BIT(pmu_gpio_wkup_en) |
749*010d6ae3SXiaoDong Huang 			   BIT(pmu_timer_wkup_en);
750*010d6ae3SXiaoDong Huang 
751*010d6ae3SXiaoDong Huang 	/* set pmic_sleep iomux gpio0_a4 */
752*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX,
753*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x3, 8));
754*010d6ae3SXiaoDong Huang 
755*010d6ae3SXiaoDong Huang 	clk_freq_khz = 32;
756*010d6ae3SXiaoDong Huang 
757*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_OSC_CNT_LO,
758*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff));
759*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_OSC_CNT_HI,
760*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16));
761*010d6ae3SXiaoDong Huang 
762*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_STABLE_CNT_LO,
763*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff));
764*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_STABLE_CNT_HI,
765*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16));
766*010d6ae3SXiaoDong Huang 
767*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_LO,
768*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 2 & 0xffff));
769*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_HI,
770*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(clk_freq_khz * 2 >> 16));
771*010d6ae3SXiaoDong Huang 
772*010d6ae3SXiaoDong Huang 	/* Pmu's clk has switched to 24M back When pmu FSM counts
773*010d6ae3SXiaoDong Huang 	 * the follow counters, so we should use 24M to calculate
774*010d6ae3SXiaoDong Huang 	 * these counters.
775*010d6ae3SXiaoDong Huang 	 */
776*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_LO,
777*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
778*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_HI,
779*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 >> 16));
780*010d6ae3SXiaoDong Huang 
781*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_LO,
782*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
783*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_HI,
784*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 >> 16));
785*010d6ae3SXiaoDong Huang 
786*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_LO,
787*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 5 & 0xffff));
788*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_HI,
789*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 5 >> 16));
790*010d6ae3SXiaoDong Huang 
791*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_LO,
792*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 & 0xffff));
793*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_HI,
794*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(24000 * 2 >> 16));
795*010d6ae3SXiaoDong Huang 
796*010d6ae3SXiaoDong Huang 	/* Config pmu power mode and pmu wakeup source */
797*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO,
798*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pwrmd_core_lo));
799*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI,
800*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pwrmd_core_hi));
801*010d6ae3SXiaoDong Huang 
802*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO,
803*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pwrmd_com_lo));
804*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI,
805*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pwrmd_com_hi));
806*010d6ae3SXiaoDong Huang 
807*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO,
808*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(pmu_wkup_cfg2_lo));
809*010d6ae3SXiaoDong Huang }
810*010d6ae3SXiaoDong Huang 
811*010d6ae3SXiaoDong Huang static void pmu_sleep_restore(void)
812*010d6ae3SXiaoDong Huang {
813*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO,
814*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_l));
815*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI,
816*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_h));
817*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO,
818*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_l));
819*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI,
820*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_h));
821*010d6ae3SXiaoDong Huang 	mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO,
822*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmu_wkup_cfg2_l));
823*010d6ae3SXiaoDong Huang 
824*010d6ae3SXiaoDong Huang 	/* restore pmic_sleep iomux */
825*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX,
826*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.pmic_slp_iomux));
827*010d6ae3SXiaoDong Huang }
828*010d6ae3SXiaoDong Huang 
829*010d6ae3SXiaoDong Huang static void soc_sleep_config(void)
830*010d6ae3SXiaoDong Huang {
831*010d6ae3SXiaoDong Huang 	ddr_data.gpio0c_iomux = mmio_read_32(PMUGRF_BASE + GPIO0C_IOMUX);
832*010d6ae3SXiaoDong Huang 
833*010d6ae3SXiaoDong Huang 	pmu_sleep_config();
834*010d6ae3SXiaoDong Huang 
835*010d6ae3SXiaoDong Huang 	ddr_sleep_config();
836*010d6ae3SXiaoDong Huang 
837*010d6ae3SXiaoDong Huang 	pvtm_32k_config();
838*010d6ae3SXiaoDong Huang }
839*010d6ae3SXiaoDong Huang 
840*010d6ae3SXiaoDong Huang static void soc_sleep_restore(void)
841*010d6ae3SXiaoDong Huang {
842*010d6ae3SXiaoDong Huang 	secure_timer_init();
843*010d6ae3SXiaoDong Huang 
844*010d6ae3SXiaoDong Huang 	pvtm_32k_config_restore();
845*010d6ae3SXiaoDong Huang 
846*010d6ae3SXiaoDong Huang 	ddr_sleep_config_restore();
847*010d6ae3SXiaoDong Huang 
848*010d6ae3SXiaoDong Huang 	pmu_sleep_restore();
849*010d6ae3SXiaoDong Huang 
850*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + GPIO0C_IOMUX,
851*010d6ae3SXiaoDong Huang 		      WITH_16BITS_WMSK(ddr_data.gpio0c_iomux));
852*010d6ae3SXiaoDong Huang }
853*010d6ae3SXiaoDong Huang 
854*010d6ae3SXiaoDong Huang static inline void pm_pll_wait_lock(uint32_t pll_base, uint32_t pll_id)
855*010d6ae3SXiaoDong Huang {
856*010d6ae3SXiaoDong Huang 	uint32_t delay = PLL_LOCKED_TIMEOUT;
857*010d6ae3SXiaoDong Huang 
858*010d6ae3SXiaoDong Huang 	while (delay > 0) {
859*010d6ae3SXiaoDong Huang 		if (mmio_read_32(pll_base + PLL_CON(1)) &
860*010d6ae3SXiaoDong Huang 		    PLL_LOCK_MSK)
861*010d6ae3SXiaoDong Huang 			break;
862*010d6ae3SXiaoDong Huang 		delay--;
863*010d6ae3SXiaoDong Huang 	}
864*010d6ae3SXiaoDong Huang 
865*010d6ae3SXiaoDong Huang 	if (delay == 0)
866*010d6ae3SXiaoDong Huang 		ERROR("Can't wait pll:%d lock\n", pll_id);
867*010d6ae3SXiaoDong Huang }
868*010d6ae3SXiaoDong Huang 
869*010d6ae3SXiaoDong Huang static inline void pll_pwr_ctr(uint32_t pll_base, uint32_t pll_id, uint32_t pd)
870*010d6ae3SXiaoDong Huang {
871*010d6ae3SXiaoDong Huang 	mmio_write_32(pll_base + PLL_CON(1),
872*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 1, 15));
873*010d6ae3SXiaoDong Huang 	if (pd)
874*010d6ae3SXiaoDong Huang 		mmio_write_32(pll_base + PLL_CON(1),
875*010d6ae3SXiaoDong Huang 			      BITS_WITH_WMASK(1, 1, 14));
876*010d6ae3SXiaoDong Huang 	else
877*010d6ae3SXiaoDong Huang 		mmio_write_32(pll_base + PLL_CON(1),
878*010d6ae3SXiaoDong Huang 			      BITS_WITH_WMASK(0, 1, 14));
879*010d6ae3SXiaoDong Huang }
880*010d6ae3SXiaoDong Huang 
881*010d6ae3SXiaoDong Huang static inline void pll_set_mode(uint32_t pll_id, uint32_t mode)
882*010d6ae3SXiaoDong Huang {
883*010d6ae3SXiaoDong Huang 	uint32_t val = BITS_WITH_WMASK(mode, 0x3, PLL_MODE_SHIFT(pll_id));
884*010d6ae3SXiaoDong Huang 
885*010d6ae3SXiaoDong Huang 	if (pll_id != GPLL_ID)
886*010d6ae3SXiaoDong Huang 		mmio_write_32(CRU_BASE + CRU_MODE, val);
887*010d6ae3SXiaoDong Huang 	else
888*010d6ae3SXiaoDong Huang 		mmio_write_32(PMUCRU_BASE + CRU_PMU_MODE,
889*010d6ae3SXiaoDong Huang 			      BITS_WITH_WMASK(mode, 0x3, 0));
890*010d6ae3SXiaoDong Huang }
891*010d6ae3SXiaoDong Huang 
892*010d6ae3SXiaoDong Huang static inline void pll_suspend(uint32_t pll_id)
893*010d6ae3SXiaoDong Huang {
894*010d6ae3SXiaoDong Huang 	int i;
895*010d6ae3SXiaoDong Huang 	uint32_t pll_base;
896*010d6ae3SXiaoDong Huang 
897*010d6ae3SXiaoDong Huang 	if (pll_id != GPLL_ID)
898*010d6ae3SXiaoDong Huang 		pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0);
899*010d6ae3SXiaoDong Huang 	else
900*010d6ae3SXiaoDong Huang 		pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0);
901*010d6ae3SXiaoDong Huang 
902*010d6ae3SXiaoDong Huang 	/* save pll con */
903*010d6ae3SXiaoDong Huang 	for (i = 0; i < PLL_CON_CNT; i++)
904*010d6ae3SXiaoDong Huang 		ddr_data.cru_plls_con_save[pll_id][i] =
905*010d6ae3SXiaoDong Huang 				mmio_read_32(pll_base + PLL_CON(i));
906*010d6ae3SXiaoDong Huang 
907*010d6ae3SXiaoDong Huang 	/* slow mode */
908*010d6ae3SXiaoDong Huang 	pll_set_mode(pll_id, SLOW_MODE);
909*010d6ae3SXiaoDong Huang }
910*010d6ae3SXiaoDong Huang 
911*010d6ae3SXiaoDong Huang static inline void pll_resume(uint32_t pll_id)
912*010d6ae3SXiaoDong Huang {
913*010d6ae3SXiaoDong Huang 	uint32_t mode, pll_base;
914*010d6ae3SXiaoDong Huang 
915*010d6ae3SXiaoDong Huang 	if (pll_id != GPLL_ID) {
916*010d6ae3SXiaoDong Huang 		pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0);
917*010d6ae3SXiaoDong Huang 		mode = (ddr_data.cru_mode_save >> PLL_MODE_SHIFT(pll_id)) & 0x3;
918*010d6ae3SXiaoDong Huang 	} else {
919*010d6ae3SXiaoDong Huang 		pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0);
920*010d6ae3SXiaoDong Huang 		mode = ddr_data.cru_pmu_mode_save & 0x3;
921*010d6ae3SXiaoDong Huang 	}
922*010d6ae3SXiaoDong Huang 
923*010d6ae3SXiaoDong Huang 	/* if pll locked before suspend, we should wait atfer resume */
924*010d6ae3SXiaoDong Huang 	if (ddr_data.cru_plls_con_save[pll_id][1] & PLL_LOCK_MSK)
925*010d6ae3SXiaoDong Huang 		pm_pll_wait_lock(pll_base, pll_id);
926*010d6ae3SXiaoDong Huang 
927*010d6ae3SXiaoDong Huang 	pll_set_mode(pll_id, mode);
928*010d6ae3SXiaoDong Huang }
929*010d6ae3SXiaoDong Huang 
930*010d6ae3SXiaoDong Huang static void pm_plls_suspend(void)
931*010d6ae3SXiaoDong Huang {
932*010d6ae3SXiaoDong Huang 	ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_MODE);
933*010d6ae3SXiaoDong Huang 	ddr_data.cru_pmu_mode_save = mmio_read_32(PMUCRU_BASE + CRU_PMU_MODE);
934*010d6ae3SXiaoDong Huang 	ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(0));
935*010d6ae3SXiaoDong Huang 
936*010d6ae3SXiaoDong Huang 	pll_suspend(GPLL_ID);
937*010d6ae3SXiaoDong Huang 	pll_suspend(NPLL_ID);
938*010d6ae3SXiaoDong Huang 	pll_suspend(CPLL_ID);
939*010d6ae3SXiaoDong Huang 	pll_suspend(APLL_ID);
940*010d6ae3SXiaoDong Huang 
941*010d6ae3SXiaoDong Huang 	/* core */
942*010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
943*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 0));
944*010d6ae3SXiaoDong Huang 
945*010d6ae3SXiaoDong Huang 	/* pclk_dbg */
946*010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
947*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(0, 0xf, 8));
948*010d6ae3SXiaoDong Huang }
949*010d6ae3SXiaoDong Huang 
950*010d6ae3SXiaoDong Huang static void pm_plls_resume(void)
951*010d6ae3SXiaoDong Huang {
952*010d6ae3SXiaoDong Huang 	/* pclk_dbg */
953*010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
954*010d6ae3SXiaoDong Huang 		      ddr_data.clk_sel0 | BITS_WMSK(0xf, 8));
955*010d6ae3SXiaoDong Huang 
956*010d6ae3SXiaoDong Huang 	/* core */
957*010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0),
958*010d6ae3SXiaoDong Huang 		      ddr_data.clk_sel0 | BITS_WMSK(0xf, 0));
959*010d6ae3SXiaoDong Huang 
960*010d6ae3SXiaoDong Huang 	pll_resume(APLL_ID);
961*010d6ae3SXiaoDong Huang 	pll_resume(CPLL_ID);
962*010d6ae3SXiaoDong Huang 	pll_resume(NPLL_ID);
963*010d6ae3SXiaoDong Huang 	pll_resume(GPLL_ID);
964*010d6ae3SXiaoDong Huang }
965*010d6ae3SXiaoDong Huang 
966*010d6ae3SXiaoDong Huang int rockchip_soc_sys_pwr_dm_suspend(void)
967*010d6ae3SXiaoDong Huang {
968*010d6ae3SXiaoDong Huang 	pmu_power_domains_suspend();
969*010d6ae3SXiaoDong Huang 
970*010d6ae3SXiaoDong Huang 	clk_gate_suspend();
971*010d6ae3SXiaoDong Huang 
972*010d6ae3SXiaoDong Huang 	soc_sleep_config();
973*010d6ae3SXiaoDong Huang 
974*010d6ae3SXiaoDong Huang 	pm_plls_suspend();
975*010d6ae3SXiaoDong Huang 
976*010d6ae3SXiaoDong Huang 	psram_boot_cfg->pm_flag &= ~PM_WARM_BOOT_BIT;
977*010d6ae3SXiaoDong Huang 
978*010d6ae3SXiaoDong Huang 	return 0;
979*010d6ae3SXiaoDong Huang }
980*010d6ae3SXiaoDong Huang 
981*010d6ae3SXiaoDong Huang int rockchip_soc_sys_pwr_dm_resume(void)
982*010d6ae3SXiaoDong Huang {
983*010d6ae3SXiaoDong Huang 	psram_boot_cfg->pm_flag |= PM_WARM_BOOT_BIT;
984*010d6ae3SXiaoDong Huang 
985*010d6ae3SXiaoDong Huang 	pm_plls_resume();
986*010d6ae3SXiaoDong Huang 
987*010d6ae3SXiaoDong Huang 	soc_sleep_restore();
988*010d6ae3SXiaoDong Huang 
989*010d6ae3SXiaoDong Huang 	clk_gate_resume();
990*010d6ae3SXiaoDong Huang 
991*010d6ae3SXiaoDong Huang 	pmu_power_domains_resume();
992*010d6ae3SXiaoDong Huang 
993*010d6ae3SXiaoDong Huang 	plat_rockchip_gic_cpuif_enable();
994*010d6ae3SXiaoDong Huang 
995*010d6ae3SXiaoDong Huang 	return 0;
996*010d6ae3SXiaoDong Huang }
997*010d6ae3SXiaoDong Huang 
998*010d6ae3SXiaoDong Huang void __dead2 rockchip_soc_soft_reset(void)
999*010d6ae3SXiaoDong Huang {
1000*010d6ae3SXiaoDong Huang 	pll_set_mode(GPLL_ID, SLOW_MODE);
1001*010d6ae3SXiaoDong Huang 	pll_set_mode(CPLL_ID, SLOW_MODE);
1002*010d6ae3SXiaoDong Huang 	pll_set_mode(NPLL_ID, SLOW_MODE);
1003*010d6ae3SXiaoDong Huang 	pll_set_mode(APLL_ID, SLOW_MODE);
1004*010d6ae3SXiaoDong Huang 	dsb();
1005*010d6ae3SXiaoDong Huang 
1006*010d6ae3SXiaoDong Huang 	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE);
1007*010d6ae3SXiaoDong Huang 	dsb();
1008*010d6ae3SXiaoDong Huang 
1009*010d6ae3SXiaoDong Huang 	/*
1010*010d6ae3SXiaoDong Huang 	 * Maybe the HW needs some times to reset the system,
1011*010d6ae3SXiaoDong Huang 	 * so we do not hope the core to execute valid codes.
1012*010d6ae3SXiaoDong Huang 	 */
1013*010d6ae3SXiaoDong Huang 	psci_power_down_wfi();
1014*010d6ae3SXiaoDong Huang }
1015*010d6ae3SXiaoDong Huang 
1016*010d6ae3SXiaoDong Huang void __dead2 rockchip_soc_system_off(void)
1017*010d6ae3SXiaoDong Huang {
1018*010d6ae3SXiaoDong Huang 	uint32_t val;
1019*010d6ae3SXiaoDong Huang 
1020*010d6ae3SXiaoDong Huang 	/* set pmic_sleep pin(gpio0_a4) to gpio mode */
1021*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, BITS_WITH_WMASK(0, 0x3, 8));
1022*010d6ae3SXiaoDong Huang 
1023*010d6ae3SXiaoDong Huang 	/* config output */
1024*010d6ae3SXiaoDong Huang 	val = mmio_read_32(GPIO0_BASE + SWPORTA_DDR);
1025*010d6ae3SXiaoDong Huang 	val |= BIT(4);
1026*010d6ae3SXiaoDong Huang 	mmio_write_32(GPIO0_BASE + SWPORTA_DDR, val);
1027*010d6ae3SXiaoDong Huang 
1028*010d6ae3SXiaoDong Huang 	/* config output high level */
1029*010d6ae3SXiaoDong Huang 	val = mmio_read_32(GPIO0_BASE);
1030*010d6ae3SXiaoDong Huang 	val |= BIT(4);
1031*010d6ae3SXiaoDong Huang 	mmio_write_32(GPIO0_BASE, val);
1032*010d6ae3SXiaoDong Huang 	dsb();
1033*010d6ae3SXiaoDong Huang 
1034*010d6ae3SXiaoDong Huang 	/*
1035*010d6ae3SXiaoDong Huang 	 * Maybe the HW needs some times to reset the system,
1036*010d6ae3SXiaoDong Huang 	 * so we do not hope the core to execute valid codes.
1037*010d6ae3SXiaoDong Huang 	 */
1038*010d6ae3SXiaoDong Huang 	psci_power_down_wfi();
1039*010d6ae3SXiaoDong Huang }
1040*010d6ae3SXiaoDong Huang 
1041*010d6ae3SXiaoDong Huang void rockchip_plat_mmu_el3(void)
1042*010d6ae3SXiaoDong Huang {
1043*010d6ae3SXiaoDong Huang 	/* TODO: support the el3 for px30 SoCs */
1044*010d6ae3SXiaoDong Huang }
1045*010d6ae3SXiaoDong Huang 
1046*010d6ae3SXiaoDong Huang void plat_rockchip_pmu_init(void)
1047*010d6ae3SXiaoDong Huang {
1048*010d6ae3SXiaoDong Huang 	uint32_t cpu;
1049*010d6ae3SXiaoDong Huang 
1050*010d6ae3SXiaoDong Huang 	rockchip_pd_lock_init();
1051*010d6ae3SXiaoDong Huang 
1052*010d6ae3SXiaoDong Huang 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
1053*010d6ae3SXiaoDong Huang 		cpuson_flags[cpu] = 0;
1054*010d6ae3SXiaoDong Huang 
1055*010d6ae3SXiaoDong Huang 	psram_boot_cfg->ddr_func = (uint64_t)0;
1056*010d6ae3SXiaoDong Huang 	psram_boot_cfg->ddr_data = (uint64_t)0;
1057*010d6ae3SXiaoDong Huang 	psram_boot_cfg->sp = PSRAM_SP_TOP;
1058*010d6ae3SXiaoDong Huang 	psram_boot_cfg->ddr_flag = 0x0;
1059*010d6ae3SXiaoDong Huang 	psram_boot_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
1060*010d6ae3SXiaoDong Huang 	psram_boot_cfg->pm_flag = PM_WARM_BOOT_BIT;
1061*010d6ae3SXiaoDong Huang 
1062*010d6ae3SXiaoDong Huang 	nonboot_cpus_off();
1063*010d6ae3SXiaoDong Huang 
1064*010d6ae3SXiaoDong Huang 	/* Remap pmu_sram's base address to boot address */
1065*010d6ae3SXiaoDong Huang 	mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0),
1066*010d6ae3SXiaoDong Huang 		      BITS_WITH_WMASK(1, 0x1, 13));
1067*010d6ae3SXiaoDong Huang 
1068*010d6ae3SXiaoDong Huang 	INFO("%s: pd status %x\n",
1069*010d6ae3SXiaoDong Huang 	     __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
1070*010d6ae3SXiaoDong Huang }
1071