xref: /rk3399_ARM-atf/plat/renesas/common/plat_pm.c (revision b8ad1a16d501c7a32e72d674a70b76320dbf9a1e)
1499c2713SBiju Das /*
2*92196d4fSMarek Vasut  * Copyright (c) 2015-2025, Renesas Electronics Corporation. All rights reserved.
3499c2713SBiju Das  *
4499c2713SBiju Das  * SPDX-License-Identifier: BSD-3-Clause
5499c2713SBiju Das  */
6499c2713SBiju Das 
7499c2713SBiju Das #include <errno.h>
8499c2713SBiju Das 
9499c2713SBiju Das #include <arch_helpers.h>
10499c2713SBiju Das #include <common/bl_common.h>
11499c2713SBiju Das #include <common/debug.h>
12499c2713SBiju Das #include <drivers/arm/cci.h>
13499c2713SBiju Das #include <drivers/arm/gicv2.h>
14499c2713SBiju Das #include <lib/bakery_lock.h>
15499c2713SBiju Das #include <lib/mmio.h>
16499c2713SBiju Das #include <lib/psci/psci.h>
17499c2713SBiju Das #include <plat/common/platform.h>
18499c2713SBiju Das 
19499c2713SBiju Das #include "iic_dvfs.h"
20499c2713SBiju Das #include "platform_def.h"
21499c2713SBiju Das #include "pwrc.h"
22*92196d4fSMarek Vasut #include "timer.h"
23*92196d4fSMarek Vasut 
24499c2713SBiju Das #include "rcar_def.h"
25499c2713SBiju Das #include "rcar_private.h"
26*92196d4fSMarek Vasut 
2727bbfca9SBiju Das #if RCAR_GEN3_ULCB
28499c2713SBiju Das #include "ulcb_cpld.h"
2927bbfca9SBiju Das #endif /* RCAR_GEN3_ULCB */
30499c2713SBiju Das 
31499c2713SBiju Das #define DVFS_SET_VID_0V		(0x00)
32499c2713SBiju Das #define P_ALL_OFF		(0x80)
33499c2713SBiju Das #define KEEPON_DDR1C		(0x08)
34499c2713SBiju Das #define KEEPON_DDR0C		(0x04)
35499c2713SBiju Das #define KEEPON_DDR1		(0x02)
36499c2713SBiju Das #define KEEPON_DDR0		(0x01)
37499c2713SBiju Das 
38499c2713SBiju Das #define SYSTEM_PWR_STATE(s)	((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
39499c2713SBiju Das #define CLUSTER_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL1])
40499c2713SBiju Das #define CORE_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL0])
41499c2713SBiju Das 
42499c2713SBiju Das extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
43499c2713SBiju Das extern void plat_rcar_gic_driver_init(void);
44499c2713SBiju Das extern void plat_rcar_gic_init(void);
45499c2713SBiju Das 
46499c2713SBiju Das static uintptr_t rcar_sec_entrypoint;
47499c2713SBiju Das 
rcar_program_mailbox(u_register_t mpidr,uintptr_t address)48ffb725beSTakuya Sakata static void rcar_program_mailbox(u_register_t mpidr, uintptr_t address)
49499c2713SBiju Das {
50499c2713SBiju Das 	mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE;
51499c2713SBiju Das 	uint64_t linear_id = plat_core_pos_by_mpidr(mpidr);
52499c2713SBiju Das 	unsigned long range;
53499c2713SBiju Das 
54499c2713SBiju Das 	rcar_mboxes[linear_id].value = address;
55499c2713SBiju Das 	range = (unsigned long)&rcar_mboxes[linear_id];
56499c2713SBiju Das 
57499c2713SBiju Das 	flush_dcache_range(range, sizeof(range));
58499c2713SBiju Das }
59499c2713SBiju Das 
rcar_cpu_standby(plat_local_state_t cpu_state)60499c2713SBiju Das static void rcar_cpu_standby(plat_local_state_t cpu_state)
61499c2713SBiju Das {
62499c2713SBiju Das 	u_register_t scr_el3 = read_scr_el3();
63499c2713SBiju Das 
64499c2713SBiju Das 	write_scr_el3(scr_el3 | SCR_IRQ_BIT);
65499c2713SBiju Das 	dsb();
66499c2713SBiju Das 	wfi();
67499c2713SBiju Das 	write_scr_el3(scr_el3);
68499c2713SBiju Das }
69499c2713SBiju Das 
rcar_pwr_domain_on(u_register_t mpidr)70499c2713SBiju Das static int rcar_pwr_domain_on(u_register_t mpidr)
71499c2713SBiju Das {
72499c2713SBiju Das 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
73499c2713SBiju Das 	rcar_pwrc_cpuon(mpidr);
74499c2713SBiju Das 
75499c2713SBiju Das 	return PSCI_E_SUCCESS;
76499c2713SBiju Das }
77499c2713SBiju Das 
rcar_pwr_domain_on_finish(const psci_power_state_t * target_state)78499c2713SBiju Das static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
79499c2713SBiju Das {
80499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
81ffb725beSTakuya Sakata 	u_register_t mpidr = read_mpidr_el1();
82499c2713SBiju Das 
83499c2713SBiju Das 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
84499c2713SBiju Das 		if (cluster_type == RCAR_CLUSTER_A53A57)
85499c2713SBiju Das 			plat_cci_enable();
86499c2713SBiju Das 
87499c2713SBiju Das 	rcar_program_mailbox(mpidr, 0);
88d9912cf3STakuya Sakata 	rcar_pwrc_enable_interrupt_wakeup(mpidr);
89499c2713SBiju Das 
90499c2713SBiju Das 	gicv2_cpuif_enable();
91499c2713SBiju Das 	gicv2_pcpu_distif_init();
92499c2713SBiju Das }
93499c2713SBiju Das 
rcar_pwr_domain_off(const psci_power_state_t * target_state)94499c2713SBiju Das static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
95499c2713SBiju Das {
96499c2713SBiju Das #if RCAR_LSI != RCAR_D3
97499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
98499c2713SBiju Das #endif
99ffb725beSTakuya Sakata 	u_register_t mpidr = read_mpidr_el1();
100499c2713SBiju Das 
101d9912cf3STakuya Sakata 	rcar_pwrc_disable_interrupt_wakeup(mpidr);
102499c2713SBiju Das 	gicv2_cpuif_disable();
103499c2713SBiju Das 	rcar_pwrc_cpuoff(mpidr);
104499c2713SBiju Das 
105499c2713SBiju Das #if RCAR_LSI != RCAR_D3
106499c2713SBiju Das 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
107499c2713SBiju Das 		if (cluster_type == RCAR_CLUSTER_A53A57)
108499c2713SBiju Das 			plat_cci_disable();
109499c2713SBiju Das 
110499c2713SBiju Das 		rcar_pwrc_clusteroff(mpidr);
111499c2713SBiju Das 	}
112499c2713SBiju Das #endif
113499c2713SBiju Das }
114499c2713SBiju Das 
rcar_pwr_domain_suspend(const psci_power_state_t * target_state)115499c2713SBiju Das static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
116499c2713SBiju Das {
117499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
118ffb725beSTakuya Sakata 	u_register_t mpidr = read_mpidr_el1();
119499c2713SBiju Das 
120499c2713SBiju Das 	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
121499c2713SBiju Das 		return;
122499c2713SBiju Das 
123499c2713SBiju Das 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
124499c2713SBiju Das 	rcar_pwrc_enable_interrupt_wakeup(mpidr);
125499c2713SBiju Das 	gicv2_cpuif_disable();
126499c2713SBiju Das 	rcar_pwrc_cpuoff(mpidr);
127499c2713SBiju Das 
128499c2713SBiju Das 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
129499c2713SBiju Das 		if (cluster_type == RCAR_CLUSTER_A53A57)
130499c2713SBiju Das 			plat_cci_disable();
131499c2713SBiju Das 
132499c2713SBiju Das 		rcar_pwrc_clusteroff(mpidr);
133499c2713SBiju Das 	}
134499c2713SBiju Das }
135499c2713SBiju Das 
rcar_pwr_domain_suspend_finish(const psci_power_state_t * target_state)136499c2713SBiju Das static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
137499c2713SBiju Das 					   *target_state)
138499c2713SBiju Das {
139499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
140499c2713SBiju Das 
141499c2713SBiju Das 	if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
142499c2713SBiju Das 		goto finish;
143499c2713SBiju Das 
144499c2713SBiju Das 	plat_rcar_gic_driver_init();
145499c2713SBiju Das 	plat_rcar_gic_init();
146499c2713SBiju Das 
147499c2713SBiju Das 	if (cluster_type == RCAR_CLUSTER_A53A57)
148499c2713SBiju Das 		plat_cci_init();
149499c2713SBiju Das 
150499c2713SBiju Das 	rcar_pwrc_restore_timer_state();
151499c2713SBiju Das 	rcar_pwrc_setup();
152499c2713SBiju Das 	rcar_pwrc_code_copy_to_system_ram();
153499c2713SBiju Das 
154499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
155499c2713SBiju Das 	rcar_pwrc_init_suspend_to_ram();
156499c2713SBiju Das #endif
157499c2713SBiju Das finish:
158499c2713SBiju Das 	rcar_pwr_domain_on_finish(target_state);
159499c2713SBiju Das }
160499c2713SBiju Das 
rcar_pwr_domain_pwr_down_wfi(const psci_power_state_t * target_state)161731aa26fSToshiyuki Ogasahara static void __dead2 rcar_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
162731aa26fSToshiyuki Ogasahara {
163731aa26fSToshiyuki Ogasahara #if RCAR_SYSTEM_SUSPEND
164731aa26fSToshiyuki Ogasahara 	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
165731aa26fSToshiyuki Ogasahara 		rcar_pwrc_suspend_to_ram();
166731aa26fSToshiyuki Ogasahara #endif
167731aa26fSToshiyuki Ogasahara 	wfi();
168731aa26fSToshiyuki Ogasahara 
169731aa26fSToshiyuki Ogasahara 	ERROR("RCAR Power Down: operation not handled.\n");
170731aa26fSToshiyuki Ogasahara 	panic();
171731aa26fSToshiyuki Ogasahara }
172731aa26fSToshiyuki Ogasahara 
rcar_system_off(void)173499c2713SBiju Das static void __dead2 rcar_system_off(void)
174499c2713SBiju Das {
175499c2713SBiju Das #if PMIC_ROHM_BD9571
176499c2713SBiju Das #if PMIC_LEVEL_MODE
177499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
178499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
179499c2713SBiju Das #else
180499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
181499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
182499c2713SBiju Das #endif
183499c2713SBiju Das #else
1841b49ba0fSTakuya Sakata 	u_register_t mpidr = read_mpidr_el1();
1851b49ba0fSTakuya Sakata 	u_register_t cpu = mpidr & 0x0000ffffU;
186499c2713SBiju Das 	int32_t rtn_on;
187499c2713SBiju Das 
1881b49ba0fSTakuya Sakata 	rtn_on = rcar_pwrc_cpu_on_check(mpidr);
189499c2713SBiju Das 
1901b49ba0fSTakuya Sakata 	if (cpu != rcar_boot_mpidr) {
191499c2713SBiju Das 		panic();
1921b49ba0fSTakuya Sakata 	}
193499c2713SBiju Das 
1941b49ba0fSTakuya Sakata 	if (rtn_on != 0) {
195499c2713SBiju Das 		panic();
1961b49ba0fSTakuya Sakata 	}
197499c2713SBiju Das 
1981b49ba0fSTakuya Sakata 	rcar_pwrc_cpuoff(mpidr);
1991b49ba0fSTakuya Sakata 	rcar_pwrc_clusteroff(mpidr);
200499c2713SBiju Das 
201499c2713SBiju Das #endif /* PMIC_ROHM_BD9571 */
202499c2713SBiju Das 	wfi();
203499c2713SBiju Das 	ERROR("RCAR System Off: operation not handled.\n");
204499c2713SBiju Das 	panic();
205499c2713SBiju Das }
206499c2713SBiju Das 
rcar_system_reset(void)207499c2713SBiju Das static void __dead2 rcar_system_reset(void)
208499c2713SBiju Das {
209499c2713SBiju Das #if PMIC_ROHM_BD9571
210499c2713SBiju Das #if PMIC_LEVEL_MODE
211499c2713SBiju Das #if RCAR_SYSTEM_RESET_KEEPON_DDR
212499c2713SBiju Das 	uint8_t mode;
213499c2713SBiju Das 	int32_t error;
214499c2713SBiju Das 
215499c2713SBiju Das 	error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
216499c2713SBiju Das 	if (error) {
217499c2713SBiju Das 		ERROR("Failed send KEEP10 magic ret=%d\n", error);
218499c2713SBiju Das 		goto done;
219499c2713SBiju Das 	}
220499c2713SBiju Das 
221499c2713SBiju Das 	error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
222499c2713SBiju Das 	if (error) {
223499c2713SBiju Das 		ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error);
224499c2713SBiju Das 		goto done;
225499c2713SBiju Das 	}
226499c2713SBiju Das 
227499c2713SBiju Das 	mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
228499c2713SBiju Das 	error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
229499c2713SBiju Das 	if (error) {
230499c2713SBiju Das 		ERROR("Failed send KEEPON_DDRx ret=%d\n", error);
231499c2713SBiju Das 		goto done;
232499c2713SBiju Das 	}
233499c2713SBiju Das 
234499c2713SBiju Das 	rcar_pwrc_set_suspend_to_ram();
235499c2713SBiju Das done:
236499c2713SBiju Das #else
237499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
238499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
239499c2713SBiju Das #endif
240499c2713SBiju Das #else
241499c2713SBiju Das #if (RCAR_GEN3_ULCB == 1)
242499c2713SBiju Das 	rcar_cpld_reset_cpu();
243499c2713SBiju Das #endif
244499c2713SBiju Das #endif
245499c2713SBiju Das #else
246499c2713SBiju Das 	rcar_pwrc_system_reset();
247499c2713SBiju Das #endif
248499c2713SBiju Das 	wfi();
249499c2713SBiju Das 
250499c2713SBiju Das 	ERROR("RCAR System Reset: operation not handled.\n");
251499c2713SBiju Das 	panic();
252499c2713SBiju Das }
253499c2713SBiju Das 
rcar_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)254499c2713SBiju Das static int rcar_validate_power_state(unsigned int power_state,
255499c2713SBiju Das 				    psci_power_state_t *req_state)
256499c2713SBiju Das {
257499c2713SBiju Das 	unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
258499c2713SBiju Das 	unsigned int pstate = psci_get_pstate_type(power_state);
259499c2713SBiju Das 	uint32_t i;
260499c2713SBiju Das 
261499c2713SBiju Das 	if (pstate == PSTATE_TYPE_STANDBY) {
262499c2713SBiju Das 		if (pwr_lvl != MPIDR_AFFLVL0)
263499c2713SBiju Das 			return PSCI_E_INVALID_PARAMS;
264499c2713SBiju Das 
265499c2713SBiju Das 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
266499c2713SBiju Das 	} else {
267499c2713SBiju Das 		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
268499c2713SBiju Das 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
269499c2713SBiju Das 	}
270499c2713SBiju Das 
271499c2713SBiju Das 	if (psci_get_pstate_id(power_state))
272499c2713SBiju Das 		return PSCI_E_INVALID_PARAMS;
273499c2713SBiju Das 
274499c2713SBiju Das 	return PSCI_E_SUCCESS;
275499c2713SBiju Das }
276499c2713SBiju Das 
277499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
rcar_get_sys_suspend_power_state(psci_power_state_t * req_state)278499c2713SBiju Das static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
279499c2713SBiju Das {
280ffb725beSTakuya Sakata 	u_register_t mpidr = read_mpidr_el1() & 0x0000ffffU;
281499c2713SBiju Das 	int i;
282499c2713SBiju Das 
283499c2713SBiju Das 	if (mpidr != rcar_boot_mpidr)
284499c2713SBiju Das 		goto deny;
285499c2713SBiju Das 
286499c2713SBiju Das 	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
287499c2713SBiju Das 		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
288499c2713SBiju Das 
289499c2713SBiju Das 	return;
290499c2713SBiju Das deny:
291499c2713SBiju Das 	/* deny system suspend entry */
292499c2713SBiju Das 	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
293499c2713SBiju Das 	for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
294499c2713SBiju Das 		req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
295499c2713SBiju Das }
296499c2713SBiju Das #endif
297499c2713SBiju Das 
298499c2713SBiju Das static const plat_psci_ops_t rcar_plat_psci_ops = {
299499c2713SBiju Das 	.cpu_standby			= rcar_cpu_standby,
300499c2713SBiju Das 	.pwr_domain_on			= rcar_pwr_domain_on,
301499c2713SBiju Das 	.pwr_domain_off			= rcar_pwr_domain_off,
302499c2713SBiju Das 	.pwr_domain_suspend		= rcar_pwr_domain_suspend,
303499c2713SBiju Das 	.pwr_domain_on_finish		= rcar_pwr_domain_on_finish,
304499c2713SBiju Das 	.pwr_domain_suspend_finish	= rcar_pwr_domain_suspend_finish,
305499c2713SBiju Das 	.system_off			= rcar_system_off,
306499c2713SBiju Das 	.system_reset			= rcar_system_reset,
307499c2713SBiju Das 	.validate_power_state		= rcar_validate_power_state,
308db5fe4f4SBoyan Karatotev 	.pwr_domain_pwr_down		= rcar_pwr_domain_pwr_down_wfi,
309499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
310499c2713SBiju Das 	.get_sys_suspend_power_state	= rcar_get_sys_suspend_power_state,
311499c2713SBiju Das #endif
312499c2713SBiju Das };
313499c2713SBiju Das 
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)314499c2713SBiju Das int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
315499c2713SBiju Das {
316499c2713SBiju Das 	*psci_ops = &rcar_plat_psci_ops;
317499c2713SBiju Das 	rcar_sec_entrypoint = sec_entrypoint;
318499c2713SBiju Das 
319499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
320499c2713SBiju Das 	rcar_pwrc_init_suspend_to_ram();
321499c2713SBiju Das #endif
322499c2713SBiju Das 	return 0;
323499c2713SBiju Das }
324499c2713SBiju Das 
325