xref: /arm-trusted-firmware/plat/renesas/common/plat_pm.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <errno.h>
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <arch_helpers.h>
10*91f16700Schasinglulu #include <common/bl_common.h>
11*91f16700Schasinglulu #include <common/debug.h>
12*91f16700Schasinglulu #include <drivers/arm/cci.h>
13*91f16700Schasinglulu #include <drivers/arm/gicv2.h>
14*91f16700Schasinglulu #include <lib/bakery_lock.h>
15*91f16700Schasinglulu #include <lib/mmio.h>
16*91f16700Schasinglulu #include <lib/psci/psci.h>
17*91f16700Schasinglulu #include <plat/common/platform.h>
18*91f16700Schasinglulu 
19*91f16700Schasinglulu #include "iic_dvfs.h"
20*91f16700Schasinglulu #include "platform_def.h"
21*91f16700Schasinglulu #include "pwrc.h"
22*91f16700Schasinglulu #include "rcar_def.h"
23*91f16700Schasinglulu #include "rcar_private.h"
24*91f16700Schasinglulu #if RCAR_GEN3_ULCB
25*91f16700Schasinglulu #include "ulcb_cpld.h"
26*91f16700Schasinglulu #endif /* RCAR_GEN3_ULCB */
27*91f16700Schasinglulu 
28*91f16700Schasinglulu #define DVFS_SET_VID_0V		(0x00)
29*91f16700Schasinglulu #define P_ALL_OFF		(0x80)
30*91f16700Schasinglulu #define KEEPON_DDR1C		(0x08)
31*91f16700Schasinglulu #define KEEPON_DDR0C		(0x04)
32*91f16700Schasinglulu #define KEEPON_DDR1		(0x02)
33*91f16700Schasinglulu #define KEEPON_DDR0		(0x01)
34*91f16700Schasinglulu 
35*91f16700Schasinglulu #define SYSTEM_PWR_STATE(s)	((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
36*91f16700Schasinglulu #define CLUSTER_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL1])
37*91f16700Schasinglulu #define CORE_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL0])
38*91f16700Schasinglulu 
39*91f16700Schasinglulu extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
40*91f16700Schasinglulu extern void plat_rcar_gic_driver_init(void);
41*91f16700Schasinglulu extern void plat_rcar_gic_init(void);
42*91f16700Schasinglulu 
43*91f16700Schasinglulu static uintptr_t rcar_sec_entrypoint;
44*91f16700Schasinglulu 
45*91f16700Schasinglulu static void rcar_program_mailbox(u_register_t mpidr, uintptr_t address)
46*91f16700Schasinglulu {
47*91f16700Schasinglulu 	mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE;
48*91f16700Schasinglulu 	uint64_t linear_id = plat_core_pos_by_mpidr(mpidr);
49*91f16700Schasinglulu 	unsigned long range;
50*91f16700Schasinglulu 
51*91f16700Schasinglulu 	rcar_mboxes[linear_id].value = address;
52*91f16700Schasinglulu 	range = (unsigned long)&rcar_mboxes[linear_id];
53*91f16700Schasinglulu 
54*91f16700Schasinglulu 	flush_dcache_range(range, sizeof(range));
55*91f16700Schasinglulu }
56*91f16700Schasinglulu 
57*91f16700Schasinglulu static void rcar_cpu_standby(plat_local_state_t cpu_state)
58*91f16700Schasinglulu {
59*91f16700Schasinglulu 	u_register_t scr_el3 = read_scr_el3();
60*91f16700Schasinglulu 
61*91f16700Schasinglulu 	write_scr_el3(scr_el3 | SCR_IRQ_BIT);
62*91f16700Schasinglulu 	dsb();
63*91f16700Schasinglulu 	wfi();
64*91f16700Schasinglulu 	write_scr_el3(scr_el3);
65*91f16700Schasinglulu }
66*91f16700Schasinglulu 
67*91f16700Schasinglulu static int rcar_pwr_domain_on(u_register_t mpidr)
68*91f16700Schasinglulu {
69*91f16700Schasinglulu 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
70*91f16700Schasinglulu 	rcar_pwrc_cpuon(mpidr);
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
73*91f16700Schasinglulu }
74*91f16700Schasinglulu 
75*91f16700Schasinglulu static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
76*91f16700Schasinglulu {
77*91f16700Schasinglulu 	uint32_t cluster_type = rcar_pwrc_get_cluster();
78*91f16700Schasinglulu 	u_register_t mpidr = read_mpidr_el1();
79*91f16700Schasinglulu 
80*91f16700Schasinglulu 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
81*91f16700Schasinglulu 		if (cluster_type == RCAR_CLUSTER_A53A57)
82*91f16700Schasinglulu 			plat_cci_enable();
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	rcar_program_mailbox(mpidr, 0);
85*91f16700Schasinglulu 	rcar_pwrc_enable_interrupt_wakeup(mpidr);
86*91f16700Schasinglulu 
87*91f16700Schasinglulu 	gicv2_cpuif_enable();
88*91f16700Schasinglulu 	gicv2_pcpu_distif_init();
89*91f16700Schasinglulu }
90*91f16700Schasinglulu 
91*91f16700Schasinglulu static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
92*91f16700Schasinglulu {
93*91f16700Schasinglulu #if RCAR_LSI != RCAR_D3
94*91f16700Schasinglulu 	uint32_t cluster_type = rcar_pwrc_get_cluster();
95*91f16700Schasinglulu #endif
96*91f16700Schasinglulu 	u_register_t mpidr = read_mpidr_el1();
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	rcar_pwrc_disable_interrupt_wakeup(mpidr);
99*91f16700Schasinglulu 	gicv2_cpuif_disable();
100*91f16700Schasinglulu 	rcar_pwrc_cpuoff(mpidr);
101*91f16700Schasinglulu 
102*91f16700Schasinglulu #if RCAR_LSI != RCAR_D3
103*91f16700Schasinglulu 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
104*91f16700Schasinglulu 		if (cluster_type == RCAR_CLUSTER_A53A57)
105*91f16700Schasinglulu 			plat_cci_disable();
106*91f16700Schasinglulu 
107*91f16700Schasinglulu 		rcar_pwrc_clusteroff(mpidr);
108*91f16700Schasinglulu 	}
109*91f16700Schasinglulu #endif
110*91f16700Schasinglulu }
111*91f16700Schasinglulu 
112*91f16700Schasinglulu static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
113*91f16700Schasinglulu {
114*91f16700Schasinglulu 	uint32_t cluster_type = rcar_pwrc_get_cluster();
115*91f16700Schasinglulu 	u_register_t mpidr = read_mpidr_el1();
116*91f16700Schasinglulu 
117*91f16700Schasinglulu 	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
118*91f16700Schasinglulu 		return;
119*91f16700Schasinglulu 
120*91f16700Schasinglulu 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
121*91f16700Schasinglulu 	rcar_pwrc_enable_interrupt_wakeup(mpidr);
122*91f16700Schasinglulu 	gicv2_cpuif_disable();
123*91f16700Schasinglulu 	rcar_pwrc_cpuoff(mpidr);
124*91f16700Schasinglulu 
125*91f16700Schasinglulu 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
126*91f16700Schasinglulu 		if (cluster_type == RCAR_CLUSTER_A53A57)
127*91f16700Schasinglulu 			plat_cci_disable();
128*91f16700Schasinglulu 
129*91f16700Schasinglulu 		rcar_pwrc_clusteroff(mpidr);
130*91f16700Schasinglulu 	}
131*91f16700Schasinglulu }
132*91f16700Schasinglulu 
133*91f16700Schasinglulu static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
134*91f16700Schasinglulu 					   *target_state)
135*91f16700Schasinglulu {
136*91f16700Schasinglulu 	uint32_t cluster_type = rcar_pwrc_get_cluster();
137*91f16700Schasinglulu 
138*91f16700Schasinglulu 	if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
139*91f16700Schasinglulu 		goto finish;
140*91f16700Schasinglulu 
141*91f16700Schasinglulu 	plat_rcar_gic_driver_init();
142*91f16700Schasinglulu 	plat_rcar_gic_init();
143*91f16700Schasinglulu 
144*91f16700Schasinglulu 	if (cluster_type == RCAR_CLUSTER_A53A57)
145*91f16700Schasinglulu 		plat_cci_init();
146*91f16700Schasinglulu 
147*91f16700Schasinglulu 	rcar_pwrc_restore_timer_state();
148*91f16700Schasinglulu 	rcar_pwrc_setup();
149*91f16700Schasinglulu 	rcar_pwrc_code_copy_to_system_ram();
150*91f16700Schasinglulu 
151*91f16700Schasinglulu #if RCAR_SYSTEM_SUSPEND
152*91f16700Schasinglulu 	rcar_pwrc_init_suspend_to_ram();
153*91f16700Schasinglulu #endif
154*91f16700Schasinglulu finish:
155*91f16700Schasinglulu 	rcar_pwr_domain_on_finish(target_state);
156*91f16700Schasinglulu }
157*91f16700Schasinglulu 
158*91f16700Schasinglulu static void __dead2 rcar_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
159*91f16700Schasinglulu {
160*91f16700Schasinglulu #if RCAR_SYSTEM_SUSPEND
161*91f16700Schasinglulu 	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
162*91f16700Schasinglulu 		rcar_pwrc_suspend_to_ram();
163*91f16700Schasinglulu #endif
164*91f16700Schasinglulu 	wfi();
165*91f16700Schasinglulu 
166*91f16700Schasinglulu 	ERROR("RCAR Power Down: operation not handled.\n");
167*91f16700Schasinglulu 	panic();
168*91f16700Schasinglulu }
169*91f16700Schasinglulu 
170*91f16700Schasinglulu static void __dead2 rcar_system_off(void)
171*91f16700Schasinglulu {
172*91f16700Schasinglulu #if PMIC_ROHM_BD9571
173*91f16700Schasinglulu #if PMIC_LEVEL_MODE
174*91f16700Schasinglulu 	if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
175*91f16700Schasinglulu 		ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
176*91f16700Schasinglulu #else
177*91f16700Schasinglulu 	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
178*91f16700Schasinglulu 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
179*91f16700Schasinglulu #endif
180*91f16700Schasinglulu #else
181*91f16700Schasinglulu 	u_register_t mpidr = read_mpidr_el1();
182*91f16700Schasinglulu 	u_register_t cpu = mpidr & 0x0000ffffU;
183*91f16700Schasinglulu 	int32_t rtn_on;
184*91f16700Schasinglulu 
185*91f16700Schasinglulu 	rtn_on = rcar_pwrc_cpu_on_check(mpidr);
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	if (cpu != rcar_boot_mpidr) {
188*91f16700Schasinglulu 		panic();
189*91f16700Schasinglulu 	}
190*91f16700Schasinglulu 
191*91f16700Schasinglulu 	if (rtn_on != 0) {
192*91f16700Schasinglulu 		panic();
193*91f16700Schasinglulu 	}
194*91f16700Schasinglulu 
195*91f16700Schasinglulu 	rcar_pwrc_cpuoff(mpidr);
196*91f16700Schasinglulu 	rcar_pwrc_clusteroff(mpidr);
197*91f16700Schasinglulu 
198*91f16700Schasinglulu #endif /* PMIC_ROHM_BD9571 */
199*91f16700Schasinglulu 	wfi();
200*91f16700Schasinglulu 	ERROR("RCAR System Off: operation not handled.\n");
201*91f16700Schasinglulu 	panic();
202*91f16700Schasinglulu }
203*91f16700Schasinglulu 
204*91f16700Schasinglulu static void __dead2 rcar_system_reset(void)
205*91f16700Schasinglulu {
206*91f16700Schasinglulu #if PMIC_ROHM_BD9571
207*91f16700Schasinglulu #if PMIC_LEVEL_MODE
208*91f16700Schasinglulu #if RCAR_SYSTEM_RESET_KEEPON_DDR
209*91f16700Schasinglulu 	uint8_t mode;
210*91f16700Schasinglulu 	int32_t error;
211*91f16700Schasinglulu 
212*91f16700Schasinglulu 	error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
213*91f16700Schasinglulu 	if (error) {
214*91f16700Schasinglulu 		ERROR("Failed send KEEP10 magic ret=%d\n", error);
215*91f16700Schasinglulu 		goto done;
216*91f16700Schasinglulu 	}
217*91f16700Schasinglulu 
218*91f16700Schasinglulu 	error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
219*91f16700Schasinglulu 	if (error) {
220*91f16700Schasinglulu 		ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error);
221*91f16700Schasinglulu 		goto done;
222*91f16700Schasinglulu 	}
223*91f16700Schasinglulu 
224*91f16700Schasinglulu 	mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
225*91f16700Schasinglulu 	error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
226*91f16700Schasinglulu 	if (error) {
227*91f16700Schasinglulu 		ERROR("Failed send KEEPON_DDRx ret=%d\n", error);
228*91f16700Schasinglulu 		goto done;
229*91f16700Schasinglulu 	}
230*91f16700Schasinglulu 
231*91f16700Schasinglulu 	rcar_pwrc_set_suspend_to_ram();
232*91f16700Schasinglulu done:
233*91f16700Schasinglulu #else
234*91f16700Schasinglulu 	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
235*91f16700Schasinglulu 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
236*91f16700Schasinglulu #endif
237*91f16700Schasinglulu #else
238*91f16700Schasinglulu #if (RCAR_GEN3_ULCB == 1)
239*91f16700Schasinglulu 	rcar_cpld_reset_cpu();
240*91f16700Schasinglulu #endif
241*91f16700Schasinglulu #endif
242*91f16700Schasinglulu #else
243*91f16700Schasinglulu 	rcar_pwrc_system_reset();
244*91f16700Schasinglulu #endif
245*91f16700Schasinglulu 	wfi();
246*91f16700Schasinglulu 
247*91f16700Schasinglulu 	ERROR("RCAR System Reset: operation not handled.\n");
248*91f16700Schasinglulu 	panic();
249*91f16700Schasinglulu }
250*91f16700Schasinglulu 
251*91f16700Schasinglulu static int rcar_validate_power_state(unsigned int power_state,
252*91f16700Schasinglulu 				    psci_power_state_t *req_state)
253*91f16700Schasinglulu {
254*91f16700Schasinglulu 	unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
255*91f16700Schasinglulu 	unsigned int pstate = psci_get_pstate_type(power_state);
256*91f16700Schasinglulu 	uint32_t i;
257*91f16700Schasinglulu 
258*91f16700Schasinglulu 	if (pstate == PSTATE_TYPE_STANDBY) {
259*91f16700Schasinglulu 		if (pwr_lvl != MPIDR_AFFLVL0)
260*91f16700Schasinglulu 			return PSCI_E_INVALID_PARAMS;
261*91f16700Schasinglulu 
262*91f16700Schasinglulu 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
263*91f16700Schasinglulu 	} else {
264*91f16700Schasinglulu 		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
265*91f16700Schasinglulu 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
266*91f16700Schasinglulu 	}
267*91f16700Schasinglulu 
268*91f16700Schasinglulu 	if (psci_get_pstate_id(power_state))
269*91f16700Schasinglulu 		return PSCI_E_INVALID_PARAMS;
270*91f16700Schasinglulu 
271*91f16700Schasinglulu 	return PSCI_E_SUCCESS;
272*91f16700Schasinglulu }
273*91f16700Schasinglulu 
274*91f16700Schasinglulu #if RCAR_SYSTEM_SUSPEND
275*91f16700Schasinglulu static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
276*91f16700Schasinglulu {
277*91f16700Schasinglulu 	u_register_t mpidr = read_mpidr_el1() & 0x0000ffffU;
278*91f16700Schasinglulu 	int i;
279*91f16700Schasinglulu 
280*91f16700Schasinglulu 	if (mpidr != rcar_boot_mpidr)
281*91f16700Schasinglulu 		goto deny;
282*91f16700Schasinglulu 
283*91f16700Schasinglulu 	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
284*91f16700Schasinglulu 		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
285*91f16700Schasinglulu 
286*91f16700Schasinglulu 	return;
287*91f16700Schasinglulu deny:
288*91f16700Schasinglulu 	/* deny system suspend entry */
289*91f16700Schasinglulu 	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
290*91f16700Schasinglulu 	for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
291*91f16700Schasinglulu 		req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
292*91f16700Schasinglulu }
293*91f16700Schasinglulu #endif
294*91f16700Schasinglulu 
295*91f16700Schasinglulu static const plat_psci_ops_t rcar_plat_psci_ops = {
296*91f16700Schasinglulu 	.cpu_standby			= rcar_cpu_standby,
297*91f16700Schasinglulu 	.pwr_domain_on			= rcar_pwr_domain_on,
298*91f16700Schasinglulu 	.pwr_domain_off			= rcar_pwr_domain_off,
299*91f16700Schasinglulu 	.pwr_domain_suspend		= rcar_pwr_domain_suspend,
300*91f16700Schasinglulu 	.pwr_domain_on_finish		= rcar_pwr_domain_on_finish,
301*91f16700Schasinglulu 	.pwr_domain_suspend_finish	= rcar_pwr_domain_suspend_finish,
302*91f16700Schasinglulu 	.system_off			= rcar_system_off,
303*91f16700Schasinglulu 	.system_reset			= rcar_system_reset,
304*91f16700Schasinglulu 	.validate_power_state		= rcar_validate_power_state,
305*91f16700Schasinglulu 	.pwr_domain_pwr_down_wfi	= rcar_pwr_domain_pwr_down_wfi,
306*91f16700Schasinglulu #if RCAR_SYSTEM_SUSPEND
307*91f16700Schasinglulu 	.get_sys_suspend_power_state	= rcar_get_sys_suspend_power_state,
308*91f16700Schasinglulu #endif
309*91f16700Schasinglulu };
310*91f16700Schasinglulu 
311*91f16700Schasinglulu int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
312*91f16700Schasinglulu {
313*91f16700Schasinglulu 	*psci_ops = &rcar_plat_psci_ops;
314*91f16700Schasinglulu 	rcar_sec_entrypoint = sec_entrypoint;
315*91f16700Schasinglulu 
316*91f16700Schasinglulu #if RCAR_SYSTEM_SUSPEND
317*91f16700Schasinglulu 	rcar_pwrc_init_suspend_to_ram();
318*91f16700Schasinglulu #endif
319*91f16700Schasinglulu 	return 0;
320*91f16700Schasinglulu }
321*91f16700Schasinglulu 
322