xref: /rk3399_ARM-atf/plat/rockchip/rk3399/drivers/pmu/pmu.c (revision 9ec78bdfc6a8058771920aec51f82513a0e4d4f0)
16fba6e04STony Xie /*
26fba6e04STony Xie  * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
36fba6e04STony Xie  *
46fba6e04STony Xie  * Redistribution and use in source and binary forms, with or without
56fba6e04STony Xie  * modification, are permitted provided that the following conditions are met:
66fba6e04STony Xie  *
76fba6e04STony Xie  * Redistributions of source code must retain the above copyright notice, this
86fba6e04STony Xie  * list of conditions and the following disclaimer.
96fba6e04STony Xie  *
106fba6e04STony Xie  * Redistributions in binary form must reproduce the above copyright notice,
116fba6e04STony Xie  * this list of conditions and the following disclaimer in the documentation
126fba6e04STony Xie  * and/or other materials provided with the distribution.
136fba6e04STony Xie  *
146fba6e04STony Xie  * Neither the name of ARM nor the names of its contributors may be used
156fba6e04STony Xie  * to endorse or promote products derived from this software without specific
166fba6e04STony Xie  * prior written permission.
176fba6e04STony Xie  *
186fba6e04STony Xie  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
196fba6e04STony Xie  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
206fba6e04STony Xie  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
216fba6e04STony Xie  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
226fba6e04STony Xie  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
236fba6e04STony Xie  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
246fba6e04STony Xie  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
256fba6e04STony Xie  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
266fba6e04STony Xie  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
276fba6e04STony Xie  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
286fba6e04STony Xie  * POSSIBILITY OF SUCH DAMAGE.
296fba6e04STony Xie  */
306fba6e04STony Xie 
316fba6e04STony Xie #include <arch_helpers.h>
326fba6e04STony Xie #include <assert.h>
336fba6e04STony Xie #include <bakery_lock.h>
346fba6e04STony Xie #include <debug.h>
356fba6e04STony Xie #include <delay_timer.h>
366fba6e04STony Xie #include <errno.h>
378867299fSCaesar Wang #include <gpio.h>
386fba6e04STony Xie #include <mmio.h>
396fba6e04STony Xie #include <platform.h>
406fba6e04STony Xie #include <platform_def.h>
418867299fSCaesar Wang #include <plat_params.h>
426fba6e04STony Xie #include <plat_private.h>
436fba6e04STony Xie #include <rk3399_def.h>
446fba6e04STony Xie #include <pmu_sram.h>
456fba6e04STony Xie #include <soc.h>
466fba6e04STony Xie #include <pmu.h>
476fba6e04STony Xie #include <pmu_com.h>
486fba6e04STony Xie 
49*9ec78bdfSTony Xie DEFINE_BAKERY_LOCK(rockchip_pd_lock);
50*9ec78bdfSTony Xie 
516fba6e04STony Xie static struct psram_data_t *psram_sleep_cfg =
526fba6e04STony Xie 	(struct psram_data_t *)PSRAM_DT_BASE;
536fba6e04STony Xie 
54f47a25ddSCaesar Wang static uint32_t cpu_warm_boot_addr;
55f47a25ddSCaesar Wang 
566fba6e04STony Xie /*
576fba6e04STony Xie  * There are two ways to powering on or off on core.
586fba6e04STony Xie  * 1) Control it power domain into on or off in PMU_PWRDN_CON reg,
596fba6e04STony Xie  *    it is core_pwr_pd mode
606fba6e04STony Xie  * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
616fba6e04STony Xie  *     then, if the core enter into wfi, it power domain will be
626fba6e04STony Xie  *     powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode
636fba6e04STony Xie  * so we need core_pm_cfg_info to distinguish which method be used now.
646fba6e04STony Xie  */
656fba6e04STony Xie 
666fba6e04STony Xie static uint32_t core_pm_cfg_info[PLATFORM_CORE_COUNT]
676fba6e04STony Xie #if USE_COHERENT_MEM
686fba6e04STony Xie __attribute__ ((section("tzfw_coherent_mem")))
696fba6e04STony Xie #endif
706fba6e04STony Xie ;/* coheront */
716fba6e04STony Xie 
72*9ec78bdfSTony Xie static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
73*9ec78bdfSTony Xie {
74*9ec78bdfSTony Xie 	uint32_t bus_id = BIT(bus);
75*9ec78bdfSTony Xie 	uint32_t bus_req;
76*9ec78bdfSTony Xie 	uint32_t wait_cnt = 0;
77*9ec78bdfSTony Xie 	uint32_t bus_state, bus_ack;
78*9ec78bdfSTony Xie 
79*9ec78bdfSTony Xie 	if (state)
80*9ec78bdfSTony Xie 		bus_req = BIT(bus);
81*9ec78bdfSTony Xie 	else
82*9ec78bdfSTony Xie 		bus_req = 0;
83*9ec78bdfSTony Xie 
84*9ec78bdfSTony Xie 	mmio_clrsetbits_32(PMU_BASE + PMU_BUS_IDLE_REQ, bus_id, bus_req);
85*9ec78bdfSTony Xie 
86*9ec78bdfSTony Xie 	do {
87*9ec78bdfSTony Xie 		bus_state = mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & bus_id;
88*9ec78bdfSTony Xie 		bus_ack = mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK) & bus_id;
89*9ec78bdfSTony Xie 		wait_cnt++;
90*9ec78bdfSTony Xie 	} while ((bus_state != bus_req || bus_ack != bus_req) &&
91*9ec78bdfSTony Xie 		 (wait_cnt < MAX_WAIT_COUNT));
92*9ec78bdfSTony Xie 
93*9ec78bdfSTony Xie 	if (bus_state != bus_req || bus_ack != bus_req) {
94*9ec78bdfSTony Xie 		INFO("%s:st=%x(%x)\n", __func__,
95*9ec78bdfSTony Xie 		     mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST),
96*9ec78bdfSTony Xie 		     bus_state);
97*9ec78bdfSTony Xie 		INFO("%s:st=%x(%x)\n", __func__,
98*9ec78bdfSTony Xie 		     mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK),
99*9ec78bdfSTony Xie 		     bus_ack);
100*9ec78bdfSTony Xie 	}
101*9ec78bdfSTony Xie 
102*9ec78bdfSTony Xie }
103*9ec78bdfSTony Xie 
104*9ec78bdfSTony Xie struct pmu_slpdata_s pmu_slpdata;
105*9ec78bdfSTony Xie 
106*9ec78bdfSTony Xie static void qos_save(void)
107*9ec78bdfSTony Xie {
108*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
109*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.gpu_qos, GPU);
110*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_ISP0) == pmu_pd_on) {
111*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.isp0_m0_qos, ISP0_M0);
112*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.isp0_m1_qos, ISP0_M1);
113*9ec78bdfSTony Xie 	}
114*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_ISP1) == pmu_pd_on) {
115*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.isp1_m0_qos, ISP1_M0);
116*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.isp1_m1_qos, ISP1_M1);
117*9ec78bdfSTony Xie 	}
118*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
119*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.vop_big_r, VOP_BIG_R);
120*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.vop_big_w, VOP_BIG_W);
121*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.vop_little, VOP_LITTLE);
122*9ec78bdfSTony Xie 	}
123*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_HDCP) == pmu_pd_on)
124*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.hdcp_qos, HDCP);
125*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
126*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.gmac_qos, GMAC);
127*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_CCI) == pmu_pd_on) {
128*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.cci_m0_qos, CCI_M0);
129*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.cci_m1_qos, CCI_M1);
130*9ec78bdfSTony Xie 	}
131*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_SD) == pmu_pd_on)
132*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.sdmmc_qos, SDMMC);
133*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_EMMC) == pmu_pd_on)
134*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.emmc_qos, EMMC);
135*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_SDIOAUDIO) == pmu_pd_on)
136*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.sdio_qos, SDIO);
137*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_GIC) == pmu_pd_on)
138*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.gic_qos, GIC);
139*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_RGA) == pmu_pd_on) {
140*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.rga_r_qos, RGA_R);
141*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.rga_w_qos, RGA_W);
142*9ec78bdfSTony Xie 	}
143*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_IEP) == pmu_pd_on)
144*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.iep_qos, IEP);
145*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_USB3) == pmu_pd_on) {
146*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.usb_otg0_qos, USB_OTG0);
147*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.usb_otg1_qos, USB_OTG1);
148*9ec78bdfSTony Xie 	}
149*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_PERIHP) == pmu_pd_on) {
150*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.usb_host0_qos, USB_HOST0);
151*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.usb_host1_qos, USB_HOST1);
152*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.perihp_nsp_qos, PERIHP_NSP);
153*9ec78bdfSTony Xie 	}
154*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_PERILP) == pmu_pd_on) {
155*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.dmac0_qos, DMAC0);
156*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.dmac1_qos, DMAC1);
157*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.dcf_qos, DCF);
158*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.crypto0_qos, CRYPTO0);
159*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.crypto1_qos, CRYPTO1);
160*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.perilp_nsp_qos, PERILP_NSP);
161*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.perilpslv_nsp_qos, PERILPSLV_NSP);
162*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.peri_cm1_qos, PERI_CM1);
163*9ec78bdfSTony Xie 	}
164*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_VDU) == pmu_pd_on)
165*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.video_m0_qos, VIDEO_M0);
166*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_VCODEC) == pmu_pd_on) {
167*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.video_m1_r_qos, VIDEO_M1_R);
168*9ec78bdfSTony Xie 		RESTORE_QOS(pmu_slpdata.video_m1_w_qos, VIDEO_M1_W);
169*9ec78bdfSTony Xie 	}
170*9ec78bdfSTony Xie }
171*9ec78bdfSTony Xie 
172*9ec78bdfSTony Xie static void qos_restore(void)
173*9ec78bdfSTony Xie {
174*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_GPU) == pmu_pd_on)
175*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.gpu_qos, GPU);
176*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_ISP0) == pmu_pd_on) {
177*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.isp0_m0_qos, ISP0_M0);
178*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.isp0_m1_qos, ISP0_M1);
179*9ec78bdfSTony Xie 	}
180*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_ISP1) == pmu_pd_on) {
181*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.isp1_m0_qos, ISP1_M0);
182*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.isp1_m1_qos, ISP1_M1);
183*9ec78bdfSTony Xie 	}
184*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_VO) == pmu_pd_on) {
185*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.vop_big_r, VOP_BIG_R);
186*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.vop_big_w, VOP_BIG_W);
187*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.vop_little, VOP_LITTLE);
188*9ec78bdfSTony Xie 	}
189*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_HDCP) == pmu_pd_on)
190*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.hdcp_qos, HDCP);
191*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on)
192*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.gmac_qos, GMAC);
193*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_CCI) == pmu_pd_on) {
194*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.cci_m0_qos, CCI_M0);
195*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.cci_m1_qos, CCI_M1);
196*9ec78bdfSTony Xie 	}
197*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_SD) == pmu_pd_on)
198*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.sdmmc_qos, SDMMC);
199*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_EMMC) == pmu_pd_on)
200*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.emmc_qos, EMMC);
201*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_SDIOAUDIO) == pmu_pd_on)
202*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.sdio_qos, SDIO);
203*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_GIC) == pmu_pd_on)
204*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.gic_qos, GIC);
205*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_RGA) == pmu_pd_on) {
206*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.rga_r_qos, RGA_R);
207*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.rga_w_qos, RGA_W);
208*9ec78bdfSTony Xie 	}
209*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_IEP) == pmu_pd_on)
210*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.iep_qos, IEP);
211*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_USB3) == pmu_pd_on) {
212*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.usb_otg0_qos, USB_OTG0);
213*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.usb_otg1_qos, USB_OTG1);
214*9ec78bdfSTony Xie 	}
215*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_PERIHP) == pmu_pd_on) {
216*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.usb_host0_qos, USB_HOST0);
217*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.usb_host1_qos, USB_HOST1);
218*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.perihp_nsp_qos, PERIHP_NSP);
219*9ec78bdfSTony Xie 	}
220*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_PERILP) == pmu_pd_on) {
221*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.dmac0_qos, DMAC0);
222*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.dmac1_qos, DMAC1);
223*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.dcf_qos, DCF);
224*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.crypto0_qos, CRYPTO0);
225*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.crypto1_qos, CRYPTO1);
226*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.perilp_nsp_qos, PERILP_NSP);
227*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.perilpslv_nsp_qos, PERILPSLV_NSP);
228*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.peri_cm1_qos, PERI_CM1);
229*9ec78bdfSTony Xie 	}
230*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_VDU) == pmu_pd_on)
231*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.video_m0_qos, VIDEO_M0);
232*9ec78bdfSTony Xie 	if (pmu_power_domain_st(PD_VCODEC) == pmu_pd_on) {
233*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.video_m1_r_qos, VIDEO_M1_R);
234*9ec78bdfSTony Xie 		SAVE_QOS(pmu_slpdata.video_m1_w_qos, VIDEO_M1_W);
235*9ec78bdfSTony Xie 	}
236*9ec78bdfSTony Xie }
237*9ec78bdfSTony Xie 
238*9ec78bdfSTony Xie static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
239*9ec78bdfSTony Xie {
240*9ec78bdfSTony Xie 	uint32_t state;
241*9ec78bdfSTony Xie 
242*9ec78bdfSTony Xie 	if (pmu_power_domain_st(pd_id) == pd_state)
243*9ec78bdfSTony Xie 		goto out;
244*9ec78bdfSTony Xie 
245*9ec78bdfSTony Xie 	if (pd_state == pmu_pd_on)
246*9ec78bdfSTony Xie 		pmu_power_domain_ctr(pd_id, pd_state);
247*9ec78bdfSTony Xie 
248*9ec78bdfSTony Xie 	state = (pd_state == pmu_pd_off) ? BUS_IDLE : BUS_ACTIVE;
249*9ec78bdfSTony Xie 
250*9ec78bdfSTony Xie 	switch (pd_id) {
251*9ec78bdfSTony Xie 	case PD_GPU:
252*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_GPU, state);
253*9ec78bdfSTony Xie 		break;
254*9ec78bdfSTony Xie 	case PD_VIO:
255*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_VIO, state);
256*9ec78bdfSTony Xie 		break;
257*9ec78bdfSTony Xie 	case PD_ISP0:
258*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_ISP0, state);
259*9ec78bdfSTony Xie 		break;
260*9ec78bdfSTony Xie 	case PD_ISP1:
261*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_ISP1, state);
262*9ec78bdfSTony Xie 		break;
263*9ec78bdfSTony Xie 	case PD_VO:
264*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_VOPB, state);
265*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_VOPL, state);
266*9ec78bdfSTony Xie 		break;
267*9ec78bdfSTony Xie 	case PD_HDCP:
268*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_HDCP, state);
269*9ec78bdfSTony Xie 		break;
270*9ec78bdfSTony Xie 	case PD_TCPD0:
271*9ec78bdfSTony Xie 		break;
272*9ec78bdfSTony Xie 	case PD_TCPD1:
273*9ec78bdfSTony Xie 		break;
274*9ec78bdfSTony Xie 	case PD_GMAC:
275*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_GMAC, state);
276*9ec78bdfSTony Xie 		break;
277*9ec78bdfSTony Xie 	case PD_CCI:
278*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_CCIM0, state);
279*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_CCIM1, state);
280*9ec78bdfSTony Xie 		break;
281*9ec78bdfSTony Xie 	case PD_SD:
282*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_SD, state);
283*9ec78bdfSTony Xie 		break;
284*9ec78bdfSTony Xie 	case PD_EMMC:
285*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_EMMC, state);
286*9ec78bdfSTony Xie 		break;
287*9ec78bdfSTony Xie 	case PD_EDP:
288*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_EDP, state);
289*9ec78bdfSTony Xie 		break;
290*9ec78bdfSTony Xie 	case PD_SDIOAUDIO:
291*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_SDIOAUDIO, state);
292*9ec78bdfSTony Xie 		break;
293*9ec78bdfSTony Xie 	case PD_GIC:
294*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_GIC, state);
295*9ec78bdfSTony Xie 		break;
296*9ec78bdfSTony Xie 	case PD_RGA:
297*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_RGA, state);
298*9ec78bdfSTony Xie 		break;
299*9ec78bdfSTony Xie 	case PD_VCODEC:
300*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_VCODEC, state);
301*9ec78bdfSTony Xie 		break;
302*9ec78bdfSTony Xie 	case PD_VDU:
303*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_VDU, state);
304*9ec78bdfSTony Xie 		break;
305*9ec78bdfSTony Xie 	case PD_IEP:
306*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_IEP, state);
307*9ec78bdfSTony Xie 		break;
308*9ec78bdfSTony Xie 	case PD_USB3:
309*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_USB3, state);
310*9ec78bdfSTony Xie 		break;
311*9ec78bdfSTony Xie 	case PD_PERIHP:
312*9ec78bdfSTony Xie 		pmu_bus_idle_req(BUS_ID_PERIHP, state);
313*9ec78bdfSTony Xie 		break;
314*9ec78bdfSTony Xie 	default:
315*9ec78bdfSTony Xie 		break;
316*9ec78bdfSTony Xie 	}
317*9ec78bdfSTony Xie 
318*9ec78bdfSTony Xie 	if (pd_state == pmu_pd_off)
319*9ec78bdfSTony Xie 		pmu_power_domain_ctr(pd_id, pd_state);
320*9ec78bdfSTony Xie 
321*9ec78bdfSTony Xie out:
322*9ec78bdfSTony Xie 	return 0;
323*9ec78bdfSTony Xie }
324*9ec78bdfSTony Xie 
325*9ec78bdfSTony Xie static uint32_t pmu_powerdomain_state;
326*9ec78bdfSTony Xie 
327*9ec78bdfSTony Xie static void pmu_power_domains_suspend(void)
328*9ec78bdfSTony Xie {
329*9ec78bdfSTony Xie 	clk_gate_con_save();
330*9ec78bdfSTony Xie 	clk_gate_con_disable();
331*9ec78bdfSTony Xie 	qos_save();
332*9ec78bdfSTony Xie 	pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
333*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_GPU, pmu_pd_off);
334*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_TCPD0, pmu_pd_off);
335*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_TCPD1, pmu_pd_off);
336*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_VO, pmu_pd_off);
337*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_ISP0, pmu_pd_off);
338*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_ISP1, pmu_pd_off);
339*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_HDCP, pmu_pd_off);
340*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_SDIOAUDIO, pmu_pd_off);
341*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_GMAC, pmu_pd_off);
342*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_EDP, pmu_pd_off);
343*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_IEP, pmu_pd_off);
344*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_RGA, pmu_pd_off);
345*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_VCODEC, pmu_pd_off);
346*9ec78bdfSTony Xie 	pmu_set_power_domain(PD_VDU, pmu_pd_off);
347*9ec78bdfSTony Xie 	clk_gate_con_restore();
348*9ec78bdfSTony Xie }
349*9ec78bdfSTony Xie 
350*9ec78bdfSTony Xie static void pmu_power_domains_resume(void)
351*9ec78bdfSTony Xie {
352*9ec78bdfSTony Xie 	clk_gate_con_save();
353*9ec78bdfSTony Xie 	clk_gate_con_disable();
354*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_VDU)))
355*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_VDU, pmu_pd_on);
356*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_VCODEC)))
357*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_VCODEC, pmu_pd_on);
358*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_RGA)))
359*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_RGA, pmu_pd_on);
360*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_IEP)))
361*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_IEP, pmu_pd_on);
362*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_EDP)))
363*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_EDP, pmu_pd_on);
364*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_GMAC)))
365*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_GMAC, pmu_pd_on);
366*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_SDIOAUDIO)))
367*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_SDIOAUDIO, pmu_pd_on);
368*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_HDCP)))
369*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_HDCP, pmu_pd_on);
370*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_ISP1)))
371*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_ISP1, pmu_pd_on);
372*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_ISP0)))
373*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_ISP0, pmu_pd_on);
374*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_VO)))
375*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_VO, pmu_pd_on);
376*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_TCPD1)))
377*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_TCPD1, pmu_pd_on);
378*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_TCPD0)))
379*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_TCPD0, pmu_pd_on);
380*9ec78bdfSTony Xie 	if (!(pmu_powerdomain_state & BIT(PD_GPU)))
381*9ec78bdfSTony Xie 		pmu_set_power_domain(PD_GPU, pmu_pd_on);
382*9ec78bdfSTony Xie 	qos_restore();
383*9ec78bdfSTony Xie 	clk_gate_con_restore();
384*9ec78bdfSTony Xie }
385*9ec78bdfSTony Xie 
386f47a25ddSCaesar Wang void rk3399_flash_l2_b(void)
387f47a25ddSCaesar Wang {
388f47a25ddSCaesar Wang 	uint32_t wait_cnt = 0;
389f47a25ddSCaesar Wang 
390f47a25ddSCaesar Wang 	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(L2_FLUSH_REQ_CLUSTER_B));
391f47a25ddSCaesar Wang 	dsb();
392f47a25ddSCaesar Wang 
393f47a25ddSCaesar Wang 	while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) &
394f47a25ddSCaesar Wang 		 BIT(L2_FLUSHDONE_CLUSTER_B))) {
395f47a25ddSCaesar Wang 		wait_cnt++;
396*9ec78bdfSTony Xie 		if (wait_cnt >= MAX_WAIT_COUNT)
397f47a25ddSCaesar Wang 			WARN("%s:reg %x,wait\n", __func__,
398f47a25ddSCaesar Wang 			     mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST));
399f47a25ddSCaesar Wang 	}
400f47a25ddSCaesar Wang 
401f47a25ddSCaesar Wang 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(L2_FLUSH_REQ_CLUSTER_B));
402f47a25ddSCaesar Wang }
403f47a25ddSCaesar Wang 
404f47a25ddSCaesar Wang static void pmu_scu_b_pwrdn(void)
405f47a25ddSCaesar Wang {
406f47a25ddSCaesar Wang 	uint32_t wait_cnt = 0;
407f47a25ddSCaesar Wang 
408f47a25ddSCaesar Wang 	if ((mmio_read_32(PMU_BASE + PMU_PWRDN_ST) &
409f47a25ddSCaesar Wang 	     (BIT(PMU_A72_B0_PWRDWN_ST) | BIT(PMU_A72_B1_PWRDWN_ST))) !=
410f47a25ddSCaesar Wang 	     (BIT(PMU_A72_B0_PWRDWN_ST) | BIT(PMU_A72_B1_PWRDWN_ST))) {
411f47a25ddSCaesar Wang 		ERROR("%s: not all cpus is off\n", __func__);
412f47a25ddSCaesar Wang 		return;
413f47a25ddSCaesar Wang 	}
414f47a25ddSCaesar Wang 
415f47a25ddSCaesar Wang 	rk3399_flash_l2_b();
416f47a25ddSCaesar Wang 
417f47a25ddSCaesar Wang 	mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG));
418f47a25ddSCaesar Wang 
419f47a25ddSCaesar Wang 	while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) &
420f47a25ddSCaesar Wang 		 BIT(STANDBY_BY_WFIL2_CLUSTER_B))) {
421f47a25ddSCaesar Wang 		wait_cnt++;
422*9ec78bdfSTony Xie 		if (wait_cnt >= MAX_WAIT_COUNT)
423f47a25ddSCaesar Wang 			ERROR("%s:wait cluster-b l2(%x)\n", __func__,
424f47a25ddSCaesar Wang 			      mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST));
425f47a25ddSCaesar Wang 	}
426f47a25ddSCaesar Wang }
427f47a25ddSCaesar Wang 
428f47a25ddSCaesar Wang static void pmu_scu_b_pwrup(void)
429f47a25ddSCaesar Wang {
430f47a25ddSCaesar Wang 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG));
431f47a25ddSCaesar Wang }
432f47a25ddSCaesar Wang 
4336fba6e04STony Xie void plat_rockchip_pmusram_prepare(void)
4346fba6e04STony Xie {
4356fba6e04STony Xie 	uint32_t *sram_dst, *sram_src;
4366fba6e04STony Xie 	size_t sram_size = 2;
4376fba6e04STony Xie 
4386fba6e04STony Xie 	/*
4396fba6e04STony Xie 	 * pmu sram code and data prepare
4406fba6e04STony Xie 	 */
4416fba6e04STony Xie 	sram_dst = (uint32_t *)PMUSRAM_BASE;
4426fba6e04STony Xie 	sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start;
4436fba6e04STony Xie 	sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end -
4446fba6e04STony Xie 		    (uint32_t *)sram_src;
4456fba6e04STony Xie 
4466fba6e04STony Xie 	u32_align_cpy(sram_dst, sram_src, sram_size);
4476fba6e04STony Xie 
4486fba6e04STony Xie 	psram_sleep_cfg->sp = PSRAM_DT_BASE;
4496fba6e04STony Xie }
4506fba6e04STony Xie 
4516fba6e04STony Xie static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
4526fba6e04STony Xie {
45380fb66b3SSandrine Bailleux 	assert(cpu_id < PLATFORM_CORE_COUNT);
4546fba6e04STony Xie 	return core_pm_cfg_info[cpu_id];
4556fba6e04STony Xie }
4566fba6e04STony Xie 
4576fba6e04STony Xie static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value)
4586fba6e04STony Xie {
45980fb66b3SSandrine Bailleux 	assert(cpu_id < PLATFORM_CORE_COUNT);
4606fba6e04STony Xie 	core_pm_cfg_info[cpu_id] = value;
4616fba6e04STony Xie #if !USE_COHERENT_MEM
4626fba6e04STony Xie 	flush_dcache_range((uintptr_t)&core_pm_cfg_info[cpu_id],
4636fba6e04STony Xie 			   sizeof(uint32_t));
4646fba6e04STony Xie #endif
4656fba6e04STony Xie }
4666fba6e04STony Xie 
4676fba6e04STony Xie static int cpus_power_domain_on(uint32_t cpu_id)
4686fba6e04STony Xie {
4696fba6e04STony Xie 	uint32_t cfg_info;
4706fba6e04STony Xie 	uint32_t cpu_pd = PD_CPUL0 + cpu_id;
4716fba6e04STony Xie 	/*
4726fba6e04STony Xie 	  * There are two ways to powering on or off on core.
4736fba6e04STony Xie 	  * 1) Control it power domain into on or off in PMU_PWRDN_CON reg
4746fba6e04STony Xie 	  * 2) Enable the core power manage in PMU_CORE_PM_CON reg,
4756fba6e04STony Xie 	  *     then, if the core enter into wfi, it power domain will be
4766fba6e04STony Xie 	  *     powered off automatically.
4776fba6e04STony Xie 	  */
4786fba6e04STony Xie 
4796fba6e04STony Xie 	cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id);
4806fba6e04STony Xie 
4816fba6e04STony Xie 	if (cfg_info == core_pwr_pd) {
4826fba6e04STony Xie 		/* disable core_pm cfg */
4836fba6e04STony Xie 		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
4846fba6e04STony Xie 			      CORES_PM_DISABLE);
4856fba6e04STony Xie 		/* if the cores have be on, power off it firstly */
4866fba6e04STony Xie 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
4876fba6e04STony Xie 			mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), 0);
4886fba6e04STony Xie 			pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
4896fba6e04STony Xie 		}
4906fba6e04STony Xie 
4916fba6e04STony Xie 		pmu_power_domain_ctr(cpu_pd, pmu_pd_on);
4926fba6e04STony Xie 	} else {
4936fba6e04STony Xie 		if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) {
4946fba6e04STony Xie 			WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id);
4956fba6e04STony Xie 			return -EINVAL;
4966fba6e04STony Xie 		}
4976fba6e04STony Xie 
4986fba6e04STony Xie 		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
4996fba6e04STony Xie 			      BIT(core_pm_sft_wakeup_en));
500f47a25ddSCaesar Wang 		dsb();
5016fba6e04STony Xie 	}
5026fba6e04STony Xie 
5036fba6e04STony Xie 	return 0;
5046fba6e04STony Xie }
5056fba6e04STony Xie 
5066fba6e04STony Xie static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
5076fba6e04STony Xie {
5086fba6e04STony Xie 	uint32_t cpu_pd;
5096fba6e04STony Xie 	uint32_t core_pm_value;
5106fba6e04STony Xie 
5116fba6e04STony Xie 	cpu_pd = PD_CPUL0 + cpu_id;
5126fba6e04STony Xie 	if (pmu_power_domain_st(cpu_pd) == pmu_pd_off)
5136fba6e04STony Xie 		return 0;
5146fba6e04STony Xie 
5156fba6e04STony Xie 	if (pd_cfg == core_pwr_pd) {
5166fba6e04STony Xie 		if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK))
5176fba6e04STony Xie 			return -EINVAL;
5186fba6e04STony Xie 
5196fba6e04STony Xie 		/* disable core_pm cfg */
5206fba6e04STony Xie 		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
5216fba6e04STony Xie 			      CORES_PM_DISABLE);
5226fba6e04STony Xie 
5236fba6e04STony Xie 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
5246fba6e04STony Xie 		pmu_power_domain_ctr(cpu_pd, pmu_pd_off);
5256fba6e04STony Xie 	} else {
5266fba6e04STony Xie 		set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg);
5276fba6e04STony Xie 
5286fba6e04STony Xie 		core_pm_value = BIT(core_pm_en);
5296fba6e04STony Xie 		if (pd_cfg == core_pwr_wfi_int)
5306fba6e04STony Xie 			core_pm_value |= BIT(core_pm_int_wakeup_en);
5316fba6e04STony Xie 		mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
5326fba6e04STony Xie 			      core_pm_value);
533f47a25ddSCaesar Wang 		dsb();
5346fba6e04STony Xie 	}
5356fba6e04STony Xie 
5366fba6e04STony Xie 	return 0;
5376fba6e04STony Xie }
5386fba6e04STony Xie 
539*9ec78bdfSTony Xie static inline void clst_pwr_domain_suspend(plat_local_state_t lvl_state)
540*9ec78bdfSTony Xie {
541*9ec78bdfSTony Xie 	uint32_t cpu_id = plat_my_core_pos();
542*9ec78bdfSTony Xie 	uint32_t pll_id, clst_st_msk, clst_st_chk_msk, pmu_st;
543*9ec78bdfSTony Xie 
544*9ec78bdfSTony Xie 	assert(cpu_id < PLATFORM_CORE_COUNT);
545*9ec78bdfSTony Xie 
546*9ec78bdfSTony Xie 	if (lvl_state == PLAT_MAX_RET_STATE  ||
547*9ec78bdfSTony Xie 	    lvl_state == PLAT_MAX_OFF_STATE) {
548*9ec78bdfSTony Xie 		if (cpu_id < PLATFORM_CLUSTER0_CORE_COUNT) {
549*9ec78bdfSTony Xie 			pll_id = ALPLL_ID;
550*9ec78bdfSTony Xie 			clst_st_msk = CLST_L_CPUS_MSK;
551*9ec78bdfSTony Xie 		} else {
552*9ec78bdfSTony Xie 			pll_id = ABPLL_ID;
553*9ec78bdfSTony Xie 			clst_st_msk = CLST_B_CPUS_MSK <<
554*9ec78bdfSTony Xie 				       PLATFORM_CLUSTER0_CORE_COUNT;
555*9ec78bdfSTony Xie 		}
556*9ec78bdfSTony Xie 
557*9ec78bdfSTony Xie 		clst_st_chk_msk = clst_st_msk & ~(BIT(cpu_id));
558*9ec78bdfSTony Xie 
559*9ec78bdfSTony Xie 		pmu_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
560*9ec78bdfSTony Xie 
561*9ec78bdfSTony Xie 		pmu_st &= clst_st_msk;
562*9ec78bdfSTony Xie 
563*9ec78bdfSTony Xie 		if (pmu_st == clst_st_chk_msk) {
564*9ec78bdfSTony Xie 			mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3),
565*9ec78bdfSTony Xie 				      PLL_SLOW_MODE);
566*9ec78bdfSTony Xie 
567*9ec78bdfSTony Xie 			clst_warmboot_data[pll_id] = PMU_CLST_RET;
568*9ec78bdfSTony Xie 
569*9ec78bdfSTony Xie 			pmu_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST);
570*9ec78bdfSTony Xie 			pmu_st &= clst_st_msk;
571*9ec78bdfSTony Xie 			if (pmu_st == clst_st_chk_msk)
572*9ec78bdfSTony Xie 				return;
573*9ec78bdfSTony Xie 			/*
574*9ec78bdfSTony Xie 			 * it is mean that others cpu is up again,
575*9ec78bdfSTony Xie 			 * we must resume the cfg at once.
576*9ec78bdfSTony Xie 			 */
577*9ec78bdfSTony Xie 			mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3),
578*9ec78bdfSTony Xie 				      PLL_NOMAL_MODE);
579*9ec78bdfSTony Xie 			clst_warmboot_data[pll_id] = 0;
580*9ec78bdfSTony Xie 		}
581*9ec78bdfSTony Xie 	}
582*9ec78bdfSTony Xie }
583*9ec78bdfSTony Xie 
584*9ec78bdfSTony Xie static int clst_pwr_domain_resume(plat_local_state_t lvl_state)
585*9ec78bdfSTony Xie {
586*9ec78bdfSTony Xie 	uint32_t cpu_id = plat_my_core_pos();
587*9ec78bdfSTony Xie 	uint32_t pll_id, pll_st;
588*9ec78bdfSTony Xie 
589*9ec78bdfSTony Xie 	assert(cpu_id < PLATFORM_CORE_COUNT);
590*9ec78bdfSTony Xie 
591*9ec78bdfSTony Xie 	if (lvl_state == PLAT_MAX_RET_STATE ||
592*9ec78bdfSTony Xie 	    lvl_state == PLAT_MAX_OFF_STATE) {
593*9ec78bdfSTony Xie 		if (cpu_id < PLATFORM_CLUSTER0_CORE_COUNT)
594*9ec78bdfSTony Xie 			pll_id = ALPLL_ID;
595*9ec78bdfSTony Xie 		else
596*9ec78bdfSTony Xie 			pll_id = ABPLL_ID;
597*9ec78bdfSTony Xie 
598*9ec78bdfSTony Xie 		pll_st = mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 3)) >>
599*9ec78bdfSTony Xie 				 PLL_MODE_SHIFT;
600*9ec78bdfSTony Xie 
601*9ec78bdfSTony Xie 		if (pll_st != NORMAL_MODE) {
602*9ec78bdfSTony Xie 			WARN("%s: clst (%d) is in error mode (%d)\n",
603*9ec78bdfSTony Xie 			     __func__, pll_id, pll_st);
604*9ec78bdfSTony Xie 			return -1;
605*9ec78bdfSTony Xie 		}
606*9ec78bdfSTony Xie 	}
607*9ec78bdfSTony Xie 
608*9ec78bdfSTony Xie 	return 0;
609*9ec78bdfSTony Xie }
610*9ec78bdfSTony Xie 
6116fba6e04STony Xie static void nonboot_cpus_off(void)
6126fba6e04STony Xie {
6136fba6e04STony Xie 	uint32_t boot_cpu, cpu;
6146fba6e04STony Xie 
6156fba6e04STony Xie 	boot_cpu = plat_my_core_pos();
6166fba6e04STony Xie 
6176fba6e04STony Xie 	/* turn off noboot cpus */
6186fba6e04STony Xie 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
6196fba6e04STony Xie 		if (cpu == boot_cpu)
6206fba6e04STony Xie 			continue;
6216fba6e04STony Xie 		cpus_power_domain_off(cpu, core_pwr_pd);
6226fba6e04STony Xie 	}
6236fba6e04STony Xie }
6246fba6e04STony Xie 
6256fba6e04STony Xie static int cores_pwr_domain_on(unsigned long mpidr, uint64_t entrypoint)
6266fba6e04STony Xie {
6276fba6e04STony Xie 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
6286fba6e04STony Xie 
62980fb66b3SSandrine Bailleux 	assert(cpu_id < PLATFORM_CORE_COUNT);
6306fba6e04STony Xie 	assert(cpuson_flags[cpu_id] == 0);
6316fba6e04STony Xie 	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
6326fba6e04STony Xie 	cpuson_entry_point[cpu_id] = entrypoint;
6336fba6e04STony Xie 	dsb();
6346fba6e04STony Xie 
6356fba6e04STony Xie 	cpus_power_domain_on(cpu_id);
6366fba6e04STony Xie 
6376fba6e04STony Xie 	return 0;
6386fba6e04STony Xie }
6396fba6e04STony Xie 
6406fba6e04STony Xie static int cores_pwr_domain_off(void)
6416fba6e04STony Xie {
6426fba6e04STony Xie 	uint32_t cpu_id = plat_my_core_pos();
6436fba6e04STony Xie 
6446fba6e04STony Xie 	cpus_power_domain_off(cpu_id, core_pwr_wfi);
6456fba6e04STony Xie 
6466fba6e04STony Xie 	return 0;
6476fba6e04STony Xie }
6486fba6e04STony Xie 
649*9ec78bdfSTony Xie static int hlvl_pwr_domain_off(uint32_t lvl, plat_local_state_t lvl_state)
650*9ec78bdfSTony Xie {
651*9ec78bdfSTony Xie 	switch (lvl) {
652*9ec78bdfSTony Xie 	case MPIDR_AFFLVL1:
653*9ec78bdfSTony Xie 		clst_pwr_domain_suspend(lvl_state);
654*9ec78bdfSTony Xie 		break;
655*9ec78bdfSTony Xie 	default:
656*9ec78bdfSTony Xie 		break;
657*9ec78bdfSTony Xie 	}
658*9ec78bdfSTony Xie 
659*9ec78bdfSTony Xie 	return 0;
660*9ec78bdfSTony Xie }
661*9ec78bdfSTony Xie 
6626fba6e04STony Xie static int cores_pwr_domain_suspend(void)
6636fba6e04STony Xie {
6646fba6e04STony Xie 	uint32_t cpu_id = plat_my_core_pos();
6656fba6e04STony Xie 
66680fb66b3SSandrine Bailleux 	assert(cpu_id < PLATFORM_CORE_COUNT);
6676fba6e04STony Xie 	assert(cpuson_flags[cpu_id] == 0);
6686fba6e04STony Xie 	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
669*9ec78bdfSTony Xie 	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
6706fba6e04STony Xie 	dsb();
6716fba6e04STony Xie 
6726fba6e04STony Xie 	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
6736fba6e04STony Xie 
6746fba6e04STony Xie 	return 0;
6756fba6e04STony Xie }
6766fba6e04STony Xie 
677*9ec78bdfSTony Xie static int hlvl_pwr_domain_suspend(uint32_t lvl, plat_local_state_t lvl_state)
678*9ec78bdfSTony Xie {
679*9ec78bdfSTony Xie 	switch (lvl) {
680*9ec78bdfSTony Xie 	case MPIDR_AFFLVL1:
681*9ec78bdfSTony Xie 		clst_pwr_domain_suspend(lvl_state);
682*9ec78bdfSTony Xie 		break;
683*9ec78bdfSTony Xie 	default:
684*9ec78bdfSTony Xie 		break;
685*9ec78bdfSTony Xie 	}
686*9ec78bdfSTony Xie 
687*9ec78bdfSTony Xie 	return 0;
688*9ec78bdfSTony Xie }
689*9ec78bdfSTony Xie 
6906fba6e04STony Xie static int cores_pwr_domain_on_finish(void)
6916fba6e04STony Xie {
6926fba6e04STony Xie 	uint32_t cpu_id = plat_my_core_pos();
6936fba6e04STony Xie 
694*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id),
695*9ec78bdfSTony Xie 		      CORES_PM_DISABLE);
696*9ec78bdfSTony Xie 	return 0;
697*9ec78bdfSTony Xie }
698*9ec78bdfSTony Xie 
699*9ec78bdfSTony Xie static int hlvl_pwr_domain_on_finish(uint32_t lvl,
700*9ec78bdfSTony Xie 				     plat_local_state_t lvl_state)
701*9ec78bdfSTony Xie {
702*9ec78bdfSTony Xie 	switch (lvl) {
703*9ec78bdfSTony Xie 	case MPIDR_AFFLVL1:
704*9ec78bdfSTony Xie 		clst_pwr_domain_resume(lvl_state);
705*9ec78bdfSTony Xie 		break;
706*9ec78bdfSTony Xie 	default:
707*9ec78bdfSTony Xie 		break;
708*9ec78bdfSTony Xie 	}
7096fba6e04STony Xie 
7106fba6e04STony Xie 	return 0;
7116fba6e04STony Xie }
7126fba6e04STony Xie 
7136fba6e04STony Xie static int cores_pwr_domain_resume(void)
7146fba6e04STony Xie {
7156fba6e04STony Xie 	uint32_t cpu_id = plat_my_core_pos();
7166fba6e04STony Xie 
7176fba6e04STony Xie 	/* Disable core_pm */
7186fba6e04STony Xie 	mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE);
7196fba6e04STony Xie 
7206fba6e04STony Xie 	return 0;
7216fba6e04STony Xie }
7226fba6e04STony Xie 
723*9ec78bdfSTony Xie static int hlvl_pwr_domain_resume(uint32_t lvl, plat_local_state_t lvl_state)
724*9ec78bdfSTony Xie {
725*9ec78bdfSTony Xie 	switch (lvl) {
726*9ec78bdfSTony Xie 	case MPIDR_AFFLVL1:
727*9ec78bdfSTony Xie 		clst_pwr_domain_resume(lvl_state);
728*9ec78bdfSTony Xie 	default:
729*9ec78bdfSTony Xie 		break;
730*9ec78bdfSTony Xie 	}
731*9ec78bdfSTony Xie 
732*9ec78bdfSTony Xie 	return 0;
733*9ec78bdfSTony Xie }
734*9ec78bdfSTony Xie 
7356fba6e04STony Xie static void sys_slp_config(void)
7366fba6e04STony Xie {
7376fba6e04STony Xie 	uint32_t slp_mode_cfg = 0;
7386fba6e04STony Xie 
739*9ec78bdfSTony Xie 	mmio_write_32(GRF_BASE + GRF_SOC_CON4, CCI_FORCE_WAKEUP);
740f47a25ddSCaesar Wang 	mmio_write_32(PMU_BASE + PMU_CCI500_CON,
741f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_CLR_PREQ_CCI500_HW) |
742f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_CLR_QREQ_CCI500_HW) |
743f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_QGATING_CCI500_CFG));
744f47a25ddSCaesar Wang 
745f47a25ddSCaesar Wang 	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
746f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_CLR_CORE_L_HW) |
747f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_CLR_CORE_L_2GIC_HW) |
748f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_CLR_GIC2_CORE_L_HW));
749f47a25ddSCaesar Wang 
750f47a25ddSCaesar Wang 	mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1A_IOMUX,
751f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(AP_PWROFF));
752f47a25ddSCaesar Wang 
753f47a25ddSCaesar Wang 	slp_mode_cfg = BIT(PMU_PWR_MODE_EN) |
754f47a25ddSCaesar Wang 		       BIT(PMU_POWER_OFF_REQ_CFG) |
755f47a25ddSCaesar Wang 		       BIT(PMU_CPU0_PD_EN) |
756f47a25ddSCaesar Wang 		       BIT(PMU_L2_FLUSH_EN) |
757f47a25ddSCaesar Wang 		       BIT(PMU_L2_IDLE_EN) |
758*9ec78bdfSTony Xie 		       BIT(PMU_SCU_PD_EN) |
759*9ec78bdfSTony Xie 		       BIT(PMU_CCI_PD_EN) |
760*9ec78bdfSTony Xie 		       BIT(PMU_CLK_CORE_SRC_GATE_EN) |
761*9ec78bdfSTony Xie 		       BIT(PMU_PERILP_PD_EN) |
762*9ec78bdfSTony Xie 		       BIT(PMU_CLK_PERILP_SRC_GATE_EN) |
763*9ec78bdfSTony Xie 		       BIT(PMU_ALIVE_USE_LF) |
764*9ec78bdfSTony Xie 		       BIT(PMU_SREF0_ENTER_EN) |
765*9ec78bdfSTony Xie 		       BIT(PMU_SREF1_ENTER_EN) |
766*9ec78bdfSTony Xie 		       BIT(PMU_DDRC0_GATING_EN) |
767*9ec78bdfSTony Xie 		       BIT(PMU_DDRC1_GATING_EN) |
768*9ec78bdfSTony Xie 		       BIT(PMU_DDRIO0_RET_EN) |
769*9ec78bdfSTony Xie 		       BIT(PMU_DDRIO1_RET_EN) |
770*9ec78bdfSTony Xie 		       BIT(PMU_DDRIO_RET_HW_DE_REQ) |
771*9ec78bdfSTony Xie 		       BIT(PMU_PLL_PD_EN) |
772*9ec78bdfSTony Xie 		       BIT(PMU_CLK_CENTER_SRC_GATE_EN) |
773*9ec78bdfSTony Xie 		       BIT(PMU_OSC_DIS) |
774*9ec78bdfSTony Xie 		       BIT(PMU_PMU_USE_LF);
775f47a25ddSCaesar Wang 
776*9ec78bdfSTony Xie 	mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_CLUSTER_L_WKUP_EN));
777*9ec78bdfSTony Xie 	mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_CLUSTER_B_WKUP_EN));
778*9ec78bdfSTony Xie 	mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_GPIO_WKUP_EN));
7796fba6e04STony Xie 	mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg);
780f47a25ddSCaesar Wang 
781*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_32K_CNT_MS(5));
782*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_32K_CNT_MS(5));
783*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRDN_CNT, CYCL_32K_CNT_MS(5));
784*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRUP_CNT, CYCL_32K_CNT_MS(5));
785*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_CENTER_PWRDN_CNT, CYCL_32K_CNT_MS(5));
786*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_CENTER_PWRUP_CNT, CYCL_32K_CNT_MS(5));
787*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_CNT, CYCL_32K_CNT_MS(5));
788*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_OSC_CNT, CYCL_32K_CNT_MS(5));
789*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_DDRIO_PWRON_CNT, CYCL_32K_CNT_MS(5));
790*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT, CYCL_32K_CNT_MS(5));
791*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_PLLRST_CNT, CYCL_32K_CNT_MS(5));
792*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_STABLE_CNT, CYCL_32K_CNT_MS(5));
793*9ec78bdfSTony Xie 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(PMU_24M_EN_CFG));
794*9ec78bdfSTony Xie 
795*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_PLL_CON, PLL_PD_HW);
796*9ec78bdfSTony Xie 	mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON0, EXTERNAL_32K);
797*9ec78bdfSTony Xie 	mmio_write_32(PMUGRF_BASE, IOMUX_CLK_32K); /*32k iomux*/
798*9ec78bdfSTony Xie }
799*9ec78bdfSTony Xie 
800*9ec78bdfSTony Xie static void set_hw_idle(uint32_t hw_idle)
801*9ec78bdfSTony Xie {
802*9ec78bdfSTony Xie 	mmio_setbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle);
803*9ec78bdfSTony Xie }
804*9ec78bdfSTony Xie 
805*9ec78bdfSTony Xie static void clr_hw_idle(uint32_t hw_idle)
806*9ec78bdfSTony Xie {
807*9ec78bdfSTony Xie 	mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle);
8086fba6e04STony Xie }
8096fba6e04STony Xie 
8106fba6e04STony Xie static int sys_pwr_domain_suspend(void)
8116fba6e04STony Xie {
812*9ec78bdfSTony Xie 	uint32_t wait_cnt = 0;
813*9ec78bdfSTony Xie 	uint32_t status = 0;
814*9ec78bdfSTony Xie 
815*9ec78bdfSTony Xie 	pmu_power_domains_suspend();
816*9ec78bdfSTony Xie 	set_hw_idle(BIT(PMU_CLR_CENTER1) |
817*9ec78bdfSTony Xie 		    BIT(PMU_CLR_ALIVE) |
818*9ec78bdfSTony Xie 		    BIT(PMU_CLR_MSCH0) |
819*9ec78bdfSTony Xie 		    BIT(PMU_CLR_MSCH1) |
820*9ec78bdfSTony Xie 		    BIT(PMU_CLR_CCIM0) |
821*9ec78bdfSTony Xie 		    BIT(PMU_CLR_CCIM1) |
822*9ec78bdfSTony Xie 		    BIT(PMU_CLR_CENTER) |
823*9ec78bdfSTony Xie 		    BIT(PMU_CLR_PERILP) |
824*9ec78bdfSTony Xie 		    BIT(PMU_CLR_PMU) |
825*9ec78bdfSTony Xie 		    BIT(PMU_CLR_PERILPM0) |
826*9ec78bdfSTony Xie 		    BIT(PMU_CLR_GIC));
827*9ec78bdfSTony Xie 
8286fba6e04STony Xie 	sys_slp_config();
8296fba6e04STony Xie 	pmu_sgrf_rst_hld();
830f47a25ddSCaesar Wang 
831f47a25ddSCaesar Wang 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
832f47a25ddSCaesar Wang 		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
833f47a25ddSCaesar Wang 		      CPU_BOOT_ADDR_WMASK);
834f47a25ddSCaesar Wang 
835f47a25ddSCaesar Wang 	pmu_scu_b_pwrdn();
836f47a25ddSCaesar Wang 
837f47a25ddSCaesar Wang 	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
838f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
839f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_SW) |
840f47a25ddSCaesar Wang 		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_GIC2_CORE_B_SW));
841f47a25ddSCaesar Wang 	dsb();
842*9ec78bdfSTony Xie 	status = BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST) |
843*9ec78bdfSTony Xie 		BIT(PMU_PWRDWN_REQ_CORE_B_SW_ST) |
844*9ec78bdfSTony Xie 		BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST);
845*9ec78bdfSTony Xie 	while ((mmio_read_32(PMU_BASE +
846*9ec78bdfSTony Xie 	       PMU_ADB400_ST) & status) != status) {
847*9ec78bdfSTony Xie 		wait_cnt++;
848*9ec78bdfSTony Xie 		if (wait_cnt >= MAX_WAIT_COUNT) {
849*9ec78bdfSTony Xie 			ERROR("%s:wait cluster-b l2(%x)\n", __func__,
850*9ec78bdfSTony Xie 			      mmio_read_32(PMU_BASE + PMU_ADB400_ST));
851*9ec78bdfSTony Xie 			panic();
852*9ec78bdfSTony Xie 		}
853*9ec78bdfSTony Xie 	}
854f47a25ddSCaesar Wang 	mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
855f47a25ddSCaesar Wang 
856*9ec78bdfSTony Xie 	/* TODO: Wait SoC to cut off the logic_center, switch the gpio mode */
857*9ec78bdfSTony Xie 	mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, GPIO0A6_IOMUX_GPIO);
858*9ec78bdfSTony Xie 
8596fba6e04STony Xie 	return 0;
8606fba6e04STony Xie }
8616fba6e04STony Xie 
8626fba6e04STony Xie static int sys_pwr_domain_resume(void)
8636fba6e04STony Xie {
864*9ec78bdfSTony Xie 	uint32_t wait_cnt = 0;
865*9ec78bdfSTony Xie 	uint32_t status = 0;
866*9ec78bdfSTony Xie 
867*9ec78bdfSTony Xie 	/* TODO: switch the pwm mode */
868*9ec78bdfSTony Xie 	mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, GPIO0A6_IOMUX_PWM);
869*9ec78bdfSTony Xie 
870f47a25ddSCaesar Wang 	pmu_sgrf_rst_hld();
871f47a25ddSCaesar Wang 
872f47a25ddSCaesar Wang 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
873f47a25ddSCaesar Wang 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
874f47a25ddSCaesar Wang 		      CPU_BOOT_ADDR_WMASK);
875f47a25ddSCaesar Wang 
876f47a25ddSCaesar Wang 	mmio_write_32(PMU_BASE + PMU_CCI500_CON,
877f47a25ddSCaesar Wang 		      WMSK_BIT(PMU_CLR_PREQ_CCI500_HW) |
878f47a25ddSCaesar Wang 		      WMSK_BIT(PMU_CLR_QREQ_CCI500_HW) |
879f47a25ddSCaesar Wang 		      WMSK_BIT(PMU_QGATING_CCI500_CFG));
880*9ec78bdfSTony Xie 	dsb();
881f47a25ddSCaesar Wang 	mmio_clrbits_32(PMU_BASE + PMU_PWRDN_CON,
882f47a25ddSCaesar Wang 			BIT(PMU_SCU_B_PWRDWN_EN));
883f47a25ddSCaesar Wang 
884f47a25ddSCaesar Wang 	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
885f47a25ddSCaesar Wang 		      WMSK_BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
886f47a25ddSCaesar Wang 		      WMSK_BIT(PMU_PWRDWN_REQ_CORE_B_SW) |
887*9ec78bdfSTony Xie 		      WMSK_BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW) |
888*9ec78bdfSTony Xie 		      WMSK_BIT(PMU_CLR_CORE_L_HW) |
889*9ec78bdfSTony Xie 		      WMSK_BIT(PMU_CLR_CORE_L_2GIC_HW) |
890*9ec78bdfSTony Xie 		      WMSK_BIT(PMU_CLR_GIC2_CORE_L_HW));
891*9ec78bdfSTony Xie 
892*9ec78bdfSTony Xie 	status = BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST) |
893*9ec78bdfSTony Xie 		BIT(PMU_PWRDWN_REQ_CORE_B_SW_ST) |
894*9ec78bdfSTony Xie 		BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST);
895*9ec78bdfSTony Xie 
896*9ec78bdfSTony Xie 	while ((mmio_read_32(PMU_BASE +
897*9ec78bdfSTony Xie 	   PMU_ADB400_ST) & status)) {
898*9ec78bdfSTony Xie 		wait_cnt++;
899*9ec78bdfSTony Xie 		if (wait_cnt >= MAX_WAIT_COUNT) {
900*9ec78bdfSTony Xie 			ERROR("%s:wait cluster-b l2(%x)\n", __func__,
901*9ec78bdfSTony Xie 			      mmio_read_32(PMU_BASE + PMU_ADB400_ST));
902*9ec78bdfSTony Xie 			panic();
903*9ec78bdfSTony Xie 		}
904*9ec78bdfSTony Xie 	}
905f47a25ddSCaesar Wang 
906f47a25ddSCaesar Wang 	pmu_scu_b_pwrup();
907f47a25ddSCaesar Wang 
908*9ec78bdfSTony Xie 	pmu_power_domains_resume();
909*9ec78bdfSTony Xie 	clr_hw_idle(BIT(PMU_CLR_CENTER1) |
910*9ec78bdfSTony Xie 				BIT(PMU_CLR_ALIVE) |
911*9ec78bdfSTony Xie 				BIT(PMU_CLR_MSCH0) |
912*9ec78bdfSTony Xie 				BIT(PMU_CLR_MSCH1) |
913*9ec78bdfSTony Xie 				BIT(PMU_CLR_CCIM0) |
914*9ec78bdfSTony Xie 				BIT(PMU_CLR_CCIM1) |
915*9ec78bdfSTony Xie 				BIT(PMU_CLR_CENTER) |
916*9ec78bdfSTony Xie 				BIT(PMU_CLR_PERILP) |
917*9ec78bdfSTony Xie 				BIT(PMU_CLR_PMU) |
918*9ec78bdfSTony Xie 				BIT(PMU_CLR_GIC));
9196fba6e04STony Xie 	return 0;
9206fba6e04STony Xie }
9216fba6e04STony Xie 
9228867299fSCaesar Wang void __dead2 soc_soft_reset(void)
9238867299fSCaesar Wang {
9248867299fSCaesar Wang 	struct gpio_info *rst_gpio;
9258867299fSCaesar Wang 
9268867299fSCaesar Wang 	rst_gpio = (struct gpio_info *)plat_get_rockchip_gpio_reset();
9278867299fSCaesar Wang 
9288867299fSCaesar Wang 	if (rst_gpio) {
9298867299fSCaesar Wang 		gpio_set_direction(rst_gpio->index, GPIO_DIR_OUT);
9308867299fSCaesar Wang 		gpio_set_value(rst_gpio->index, rst_gpio->polarity);
9318867299fSCaesar Wang 	} else {
9328867299fSCaesar Wang 		soc_global_soft_reset();
9338867299fSCaesar Wang 	}
9348867299fSCaesar Wang 
9358867299fSCaesar Wang 	while (1)
9368867299fSCaesar Wang 		;
9378867299fSCaesar Wang }
9388867299fSCaesar Wang 
93986c253e4SCaesar Wang void __dead2 soc_system_off(void)
94086c253e4SCaesar Wang {
94186c253e4SCaesar Wang 	struct gpio_info *poweroff_gpio;
94286c253e4SCaesar Wang 
94386c253e4SCaesar Wang 	poweroff_gpio = (struct gpio_info *)plat_get_rockchip_gpio_poweroff();
94486c253e4SCaesar Wang 
94586c253e4SCaesar Wang 	if (poweroff_gpio) {
94686c253e4SCaesar Wang 		/*
94786c253e4SCaesar Wang 		 * if use tsadc over temp pin(GPIO1A6) as shutdown gpio,
94886c253e4SCaesar Wang 		 * need to set this pin iomux back to gpio function
94986c253e4SCaesar Wang 		 */
95086c253e4SCaesar Wang 		if (poweroff_gpio->index == TSADC_INT_PIN) {
95186c253e4SCaesar Wang 			mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1A_IOMUX,
95286c253e4SCaesar Wang 				      GPIO1A6_IOMUX);
95386c253e4SCaesar Wang 		}
95486c253e4SCaesar Wang 		gpio_set_direction(poweroff_gpio->index, GPIO_DIR_OUT);
95586c253e4SCaesar Wang 		gpio_set_value(poweroff_gpio->index, poweroff_gpio->polarity);
95686c253e4SCaesar Wang 	} else {
95786c253e4SCaesar Wang 		WARN("Do nothing when system off\n");
95886c253e4SCaesar Wang 	}
95986c253e4SCaesar Wang 
96086c253e4SCaesar Wang 	while (1)
96186c253e4SCaesar Wang 		;
96286c253e4SCaesar Wang }
96386c253e4SCaesar Wang 
9646fba6e04STony Xie static struct rockchip_pm_ops_cb pm_ops = {
9656fba6e04STony Xie 	.cores_pwr_dm_on = cores_pwr_domain_on,
9666fba6e04STony Xie 	.cores_pwr_dm_off = cores_pwr_domain_off,
9676fba6e04STony Xie 	.cores_pwr_dm_on_finish = cores_pwr_domain_on_finish,
9686fba6e04STony Xie 	.cores_pwr_dm_suspend = cores_pwr_domain_suspend,
9696fba6e04STony Xie 	.cores_pwr_dm_resume = cores_pwr_domain_resume,
970*9ec78bdfSTony Xie 	.hlvl_pwr_dm_suspend = hlvl_pwr_domain_suspend,
971*9ec78bdfSTony Xie 	.hlvl_pwr_dm_resume = hlvl_pwr_domain_resume,
972*9ec78bdfSTony Xie 	.hlvl_pwr_dm_off = hlvl_pwr_domain_off,
973*9ec78bdfSTony Xie 	.hlvl_pwr_dm_on_finish = hlvl_pwr_domain_on_finish,
9746fba6e04STony Xie 	.sys_pwr_dm_suspend = sys_pwr_domain_suspend,
9756fba6e04STony Xie 	.sys_pwr_dm_resume = sys_pwr_domain_resume,
9768867299fSCaesar Wang 	.sys_gbl_soft_reset = soc_soft_reset,
97786c253e4SCaesar Wang 	.system_off = soc_system_off,
9786fba6e04STony Xie };
9796fba6e04STony Xie 
9806fba6e04STony Xie void plat_rockchip_pmu_init(void)
9816fba6e04STony Xie {
9826fba6e04STony Xie 	uint32_t cpu;
9836fba6e04STony Xie 
9846fba6e04STony Xie 	rockchip_pd_lock_init();
9856fba6e04STony Xie 	plat_setup_rockchip_pm_ops(&pm_ops);
9866fba6e04STony Xie 
987f47a25ddSCaesar Wang 	/* register requires 32bits mode, switch it to 32 bits */
988f47a25ddSCaesar Wang 	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
989f47a25ddSCaesar Wang 
9906fba6e04STony Xie 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
9916fba6e04STony Xie 		cpuson_flags[cpu] = 0;
9926fba6e04STony Xie 
993*9ec78bdfSTony Xie 	for (cpu = 0; cpu < PLATFORM_CLUSTER_COUNT; cpu++)
994*9ec78bdfSTony Xie 		clst_warmboot_data[cpu] = 0;
995*9ec78bdfSTony Xie 
996f47a25ddSCaesar Wang 	psram_sleep_cfg->ddr_func = 0x00;
997f47a25ddSCaesar Wang 	psram_sleep_cfg->ddr_data = 0x00;
998f47a25ddSCaesar Wang 	psram_sleep_cfg->ddr_flag = 0x00;
9996fba6e04STony Xie 	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
10006fba6e04STony Xie 
1001*9ec78bdfSTony Xie 	/* config cpu's warm boot address */
10026fba6e04STony Xie 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
1003f47a25ddSCaesar Wang 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
10046fba6e04STony Xie 		      CPU_BOOT_ADDR_WMASK);
1005*9ec78bdfSTony Xie 	mmio_write_32(PMU_BASE + PMU_NOC_AUTO_ENA, NOC_AUTO_ENABLE);
10066fba6e04STony Xie 
10076fba6e04STony Xie 	nonboot_cpus_off();
1008f47a25ddSCaesar Wang 
10096fba6e04STony Xie 	INFO("%s(%d): pd status %x\n", __func__, __LINE__,
10106fba6e04STony Xie 	     mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
10116fba6e04STony Xie }
1012