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