xref: /rk3399_ARM-atf/plat/renesas/common/plat_pm.c (revision d9912cf3d1022fc6d38a6059290040985de56e63)
1499c2713SBiju Das /*
2731aa26fSToshiyuki Ogasahara  * Copyright (c) 2015-2021, 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"
22499c2713SBiju Das #include "rcar_def.h"
23499c2713SBiju Das #include "rcar_private.h"
2427bbfca9SBiju Das #if RCAR_GEN3_ULCB
25499c2713SBiju Das #include "ulcb_cpld.h"
2627bbfca9SBiju Das #endif /* RCAR_GEN3_ULCB */
27499c2713SBiju Das 
28499c2713SBiju Das #define DVFS_SET_VID_0V		(0x00)
29499c2713SBiju Das #define P_ALL_OFF		(0x80)
30499c2713SBiju Das #define KEEPON_DDR1C		(0x08)
31499c2713SBiju Das #define KEEPON_DDR0C		(0x04)
32499c2713SBiju Das #define KEEPON_DDR1		(0x02)
33499c2713SBiju Das #define KEEPON_DDR0		(0x01)
34499c2713SBiju Das 
35499c2713SBiju Das #define SYSTEM_PWR_STATE(s)	((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
36499c2713SBiju Das #define CLUSTER_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL1])
37499c2713SBiju Das #define CORE_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL0])
38499c2713SBiju Das 
39499c2713SBiju Das extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
40499c2713SBiju Das extern void plat_rcar_gic_driver_init(void);
41499c2713SBiju Das extern void plat_rcar_gic_init(void);
42499c2713SBiju Das 
43499c2713SBiju Das static uintptr_t rcar_sec_entrypoint;
44499c2713SBiju Das 
45499c2713SBiju Das static void rcar_program_mailbox(uint64_t mpidr, uint64_t address)
46499c2713SBiju Das {
47499c2713SBiju Das 	mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE;
48499c2713SBiju Das 	uint64_t linear_id = plat_core_pos_by_mpidr(mpidr);
49499c2713SBiju Das 	unsigned long range;
50499c2713SBiju Das 
51499c2713SBiju Das 	rcar_mboxes[linear_id].value = address;
52499c2713SBiju Das 	range = (unsigned long)&rcar_mboxes[linear_id];
53499c2713SBiju Das 
54499c2713SBiju Das 	flush_dcache_range(range, sizeof(range));
55499c2713SBiju Das }
56499c2713SBiju Das 
57499c2713SBiju Das static void rcar_cpu_standby(plat_local_state_t cpu_state)
58499c2713SBiju Das {
59499c2713SBiju Das 	u_register_t scr_el3 = read_scr_el3();
60499c2713SBiju Das 
61499c2713SBiju Das 	write_scr_el3(scr_el3 | SCR_IRQ_BIT);
62499c2713SBiju Das 	dsb();
63499c2713SBiju Das 	wfi();
64499c2713SBiju Das 	write_scr_el3(scr_el3);
65499c2713SBiju Das }
66499c2713SBiju Das 
67499c2713SBiju Das static int rcar_pwr_domain_on(u_register_t mpidr)
68499c2713SBiju Das {
69499c2713SBiju Das 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
70499c2713SBiju Das 	rcar_pwrc_cpuon(mpidr);
71499c2713SBiju Das 
72499c2713SBiju Das 	return PSCI_E_SUCCESS;
73499c2713SBiju Das }
74499c2713SBiju Das 
75499c2713SBiju Das static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
76499c2713SBiju Das {
77499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
78499c2713SBiju Das 	unsigned long mpidr = read_mpidr_el1();
79499c2713SBiju Das 
80499c2713SBiju Das 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
81499c2713SBiju Das 		if (cluster_type == RCAR_CLUSTER_A53A57)
82499c2713SBiju Das 			plat_cci_enable();
83499c2713SBiju Das 
84499c2713SBiju Das 	rcar_program_mailbox(mpidr, 0);
85*d9912cf3STakuya Sakata 	rcar_pwrc_enable_interrupt_wakeup(mpidr);
86499c2713SBiju Das 
87499c2713SBiju Das 	gicv2_cpuif_enable();
88499c2713SBiju Das 	gicv2_pcpu_distif_init();
89499c2713SBiju Das }
90499c2713SBiju Das 
91499c2713SBiju Das static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
92499c2713SBiju Das {
93499c2713SBiju Das #if RCAR_LSI != RCAR_D3
94499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
95499c2713SBiju Das #endif
96499c2713SBiju Das 	unsigned long mpidr = read_mpidr_el1();
97499c2713SBiju Das 
98*d9912cf3STakuya Sakata 	rcar_pwrc_disable_interrupt_wakeup(mpidr);
99499c2713SBiju Das 	gicv2_cpuif_disable();
100499c2713SBiju Das 	rcar_pwrc_cpuoff(mpidr);
101499c2713SBiju Das 
102499c2713SBiju Das #if RCAR_LSI != RCAR_D3
103499c2713SBiju Das 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
104499c2713SBiju Das 		if (cluster_type == RCAR_CLUSTER_A53A57)
105499c2713SBiju Das 			plat_cci_disable();
106499c2713SBiju Das 
107499c2713SBiju Das 		rcar_pwrc_clusteroff(mpidr);
108499c2713SBiju Das 	}
109499c2713SBiju Das #endif
110499c2713SBiju Das }
111499c2713SBiju Das 
112499c2713SBiju Das static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
113499c2713SBiju Das {
114499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
115499c2713SBiju Das 	unsigned long mpidr = read_mpidr_el1();
116499c2713SBiju Das 
117499c2713SBiju Das 	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
118499c2713SBiju Das 		return;
119499c2713SBiju Das 
120499c2713SBiju Das 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
121499c2713SBiju Das 	rcar_pwrc_enable_interrupt_wakeup(mpidr);
122499c2713SBiju Das 	gicv2_cpuif_disable();
123499c2713SBiju Das 	rcar_pwrc_cpuoff(mpidr);
124499c2713SBiju Das 
125499c2713SBiju Das 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
126499c2713SBiju Das 		if (cluster_type == RCAR_CLUSTER_A53A57)
127499c2713SBiju Das 			plat_cci_disable();
128499c2713SBiju Das 
129499c2713SBiju Das 		rcar_pwrc_clusteroff(mpidr);
130499c2713SBiju Das 	}
131499c2713SBiju Das }
132499c2713SBiju Das 
133499c2713SBiju Das static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
134499c2713SBiju Das 					   *target_state)
135499c2713SBiju Das {
136499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
137499c2713SBiju Das 
138499c2713SBiju Das 	if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
139499c2713SBiju Das 		goto finish;
140499c2713SBiju Das 
141499c2713SBiju Das 	plat_rcar_gic_driver_init();
142499c2713SBiju Das 	plat_rcar_gic_init();
143499c2713SBiju Das 
144499c2713SBiju Das 	if (cluster_type == RCAR_CLUSTER_A53A57)
145499c2713SBiju Das 		plat_cci_init();
146499c2713SBiju Das 
147499c2713SBiju Das 	rcar_pwrc_restore_timer_state();
148499c2713SBiju Das 	rcar_pwrc_setup();
149499c2713SBiju Das 	rcar_pwrc_code_copy_to_system_ram();
150499c2713SBiju Das 
151499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
152499c2713SBiju Das 	rcar_pwrc_init_suspend_to_ram();
153499c2713SBiju Das #endif
154499c2713SBiju Das finish:
155499c2713SBiju Das 	rcar_pwr_domain_on_finish(target_state);
156499c2713SBiju Das }
157499c2713SBiju Das 
158731aa26fSToshiyuki Ogasahara static void __dead2 rcar_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
159731aa26fSToshiyuki Ogasahara {
160731aa26fSToshiyuki Ogasahara #if RCAR_SYSTEM_SUSPEND
161731aa26fSToshiyuki Ogasahara 	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
162731aa26fSToshiyuki Ogasahara 		rcar_pwrc_suspend_to_ram();
163731aa26fSToshiyuki Ogasahara #endif
164731aa26fSToshiyuki Ogasahara 	wfi();
165731aa26fSToshiyuki Ogasahara 
166731aa26fSToshiyuki Ogasahara 	ERROR("RCAR Power Down: operation not handled.\n");
167731aa26fSToshiyuki Ogasahara 	panic();
168731aa26fSToshiyuki Ogasahara }
169731aa26fSToshiyuki Ogasahara 
170499c2713SBiju Das static void __dead2 rcar_system_off(void)
171499c2713SBiju Das {
172499c2713SBiju Das #if PMIC_ROHM_BD9571
173499c2713SBiju Das #if PMIC_LEVEL_MODE
174499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
175499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
176499c2713SBiju Das #else
177499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
178499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
179499c2713SBiju Das #endif
180499c2713SBiju Das #else
181499c2713SBiju Das 	uint64_t cpu = read_mpidr_el1() & 0x0000ffff;
182499c2713SBiju Das 	int32_t rtn_on;
183499c2713SBiju Das 
184499c2713SBiju Das 	rtn_on = rcar_pwrc_cpu_on_check(cpu);
185499c2713SBiju Das 
186499c2713SBiju Das 	if (cpu == rcar_boot_mpidr)
187499c2713SBiju Das 		panic();
188499c2713SBiju Das 
189499c2713SBiju Das 	if (rtn_on)
190499c2713SBiju Das 		panic();
191499c2713SBiju Das 
192499c2713SBiju Das 	rcar_pwrc_cpuoff(cpu);
193499c2713SBiju Das 	rcar_pwrc_clusteroff(cpu);
194499c2713SBiju Das 
195499c2713SBiju Das #endif /* PMIC_ROHM_BD9571 */
196499c2713SBiju Das 	wfi();
197499c2713SBiju Das 	ERROR("RCAR System Off: operation not handled.\n");
198499c2713SBiju Das 	panic();
199499c2713SBiju Das }
200499c2713SBiju Das 
201499c2713SBiju Das static void __dead2 rcar_system_reset(void)
202499c2713SBiju Das {
203499c2713SBiju Das #if PMIC_ROHM_BD9571
204499c2713SBiju Das #if PMIC_LEVEL_MODE
205499c2713SBiju Das #if RCAR_SYSTEM_RESET_KEEPON_DDR
206499c2713SBiju Das 	uint8_t mode;
207499c2713SBiju Das 	int32_t error;
208499c2713SBiju Das 
209499c2713SBiju Das 	error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
210499c2713SBiju Das 	if (error) {
211499c2713SBiju Das 		ERROR("Failed send KEEP10 magic ret=%d\n", error);
212499c2713SBiju Das 		goto done;
213499c2713SBiju Das 	}
214499c2713SBiju Das 
215499c2713SBiju Das 	error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
216499c2713SBiju Das 	if (error) {
217499c2713SBiju Das 		ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error);
218499c2713SBiju Das 		goto done;
219499c2713SBiju Das 	}
220499c2713SBiju Das 
221499c2713SBiju Das 	mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
222499c2713SBiju Das 	error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
223499c2713SBiju Das 	if (error) {
224499c2713SBiju Das 		ERROR("Failed send KEEPON_DDRx ret=%d\n", error);
225499c2713SBiju Das 		goto done;
226499c2713SBiju Das 	}
227499c2713SBiju Das 
228499c2713SBiju Das 	rcar_pwrc_set_suspend_to_ram();
229499c2713SBiju Das done:
230499c2713SBiju Das #else
231499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
232499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
233499c2713SBiju Das #endif
234499c2713SBiju Das #else
235499c2713SBiju Das #if (RCAR_GEN3_ULCB == 1)
236499c2713SBiju Das 	rcar_cpld_reset_cpu();
237499c2713SBiju Das #endif
238499c2713SBiju Das #endif
239499c2713SBiju Das #else
240499c2713SBiju Das 	rcar_pwrc_system_reset();
241499c2713SBiju Das #endif
242499c2713SBiju Das 	wfi();
243499c2713SBiju Das 
244499c2713SBiju Das 	ERROR("RCAR System Reset: operation not handled.\n");
245499c2713SBiju Das 	panic();
246499c2713SBiju Das }
247499c2713SBiju Das 
248499c2713SBiju Das static int rcar_validate_power_state(unsigned int power_state,
249499c2713SBiju Das 				    psci_power_state_t *req_state)
250499c2713SBiju Das {
251499c2713SBiju Das 	unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
252499c2713SBiju Das 	unsigned int pstate = psci_get_pstate_type(power_state);
253499c2713SBiju Das 	uint32_t i;
254499c2713SBiju Das 
255499c2713SBiju Das 	if (pstate == PSTATE_TYPE_STANDBY) {
256499c2713SBiju Das 		if (pwr_lvl != MPIDR_AFFLVL0)
257499c2713SBiju Das 			return PSCI_E_INVALID_PARAMS;
258499c2713SBiju Das 
259499c2713SBiju Das 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
260499c2713SBiju Das 	} else {
261499c2713SBiju Das 		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
262499c2713SBiju Das 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
263499c2713SBiju Das 	}
264499c2713SBiju Das 
265499c2713SBiju Das 	if (psci_get_pstate_id(power_state))
266499c2713SBiju Das 		return PSCI_E_INVALID_PARAMS;
267499c2713SBiju Das 
268499c2713SBiju Das 	return PSCI_E_SUCCESS;
269499c2713SBiju Das }
270499c2713SBiju Das 
271499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
272499c2713SBiju Das static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
273499c2713SBiju Das {
274499c2713SBiju Das 	unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU;
275499c2713SBiju Das 	int i;
276499c2713SBiju Das 
277499c2713SBiju Das 	if (mpidr != rcar_boot_mpidr)
278499c2713SBiju Das 		goto deny;
279499c2713SBiju Das 
280499c2713SBiju Das 	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
281499c2713SBiju Das 		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
282499c2713SBiju Das 
283499c2713SBiju Das 	return;
284499c2713SBiju Das deny:
285499c2713SBiju Das 	/* deny system suspend entry */
286499c2713SBiju Das 	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
287499c2713SBiju Das 	for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
288499c2713SBiju Das 		req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
289499c2713SBiju Das }
290499c2713SBiju Das #endif
291499c2713SBiju Das 
292499c2713SBiju Das static const plat_psci_ops_t rcar_plat_psci_ops = {
293499c2713SBiju Das 	.cpu_standby			= rcar_cpu_standby,
294499c2713SBiju Das 	.pwr_domain_on			= rcar_pwr_domain_on,
295499c2713SBiju Das 	.pwr_domain_off			= rcar_pwr_domain_off,
296499c2713SBiju Das 	.pwr_domain_suspend		= rcar_pwr_domain_suspend,
297499c2713SBiju Das 	.pwr_domain_on_finish		= rcar_pwr_domain_on_finish,
298499c2713SBiju Das 	.pwr_domain_suspend_finish	= rcar_pwr_domain_suspend_finish,
299499c2713SBiju Das 	.system_off			= rcar_system_off,
300499c2713SBiju Das 	.system_reset			= rcar_system_reset,
301499c2713SBiju Das 	.validate_power_state		= rcar_validate_power_state,
302731aa26fSToshiyuki Ogasahara 	.pwr_domain_pwr_down_wfi	= rcar_pwr_domain_pwr_down_wfi,
303499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
304499c2713SBiju Das 	.get_sys_suspend_power_state	= rcar_get_sys_suspend_power_state,
305499c2713SBiju Das #endif
306499c2713SBiju Das };
307499c2713SBiju Das 
308499c2713SBiju Das int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
309499c2713SBiju Das {
310499c2713SBiju Das 	*psci_ops = &rcar_plat_psci_ops;
311499c2713SBiju Das 	rcar_sec_entrypoint = sec_entrypoint;
312499c2713SBiju Das 
313499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
314499c2713SBiju Das 	rcar_pwrc_init_suspend_to_ram();
315499c2713SBiju Das #endif
316499c2713SBiju Das 	return 0;
317499c2713SBiju Das }
318499c2713SBiju Das 
319