xref: /rk3399_ARM-atf/plat/renesas/common/plat_pm.c (revision 27bbfca97587bc2073967dd1eea1076c6da41275)
1499c2713SBiju Das /*
2499c2713SBiju Das  * Copyright (c) 2015-2020, 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"
24*27bbfca9SBiju Das #if RCAR_GEN3_ULCB
25499c2713SBiju Das #include "ulcb_cpld.h"
26*27bbfca9SBiju 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 extern u_register_t rcar_boot_mpidr;
43499c2713SBiju Das 
44499c2713SBiju Das static uintptr_t rcar_sec_entrypoint;
45499c2713SBiju Das 
46499c2713SBiju Das static void rcar_program_mailbox(uint64_t mpidr, uint64_t address)
47499c2713SBiju Das {
48499c2713SBiju Das 	mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE;
49499c2713SBiju Das 	uint64_t linear_id = plat_core_pos_by_mpidr(mpidr);
50499c2713SBiju Das 	unsigned long range;
51499c2713SBiju Das 
52499c2713SBiju Das 	rcar_mboxes[linear_id].value = address;
53499c2713SBiju Das 	range = (unsigned long)&rcar_mboxes[linear_id];
54499c2713SBiju Das 
55499c2713SBiju Das 	flush_dcache_range(range, sizeof(range));
56499c2713SBiju Das }
57499c2713SBiju Das 
58499c2713SBiju Das static void rcar_cpu_standby(plat_local_state_t cpu_state)
59499c2713SBiju Das {
60499c2713SBiju Das 	u_register_t scr_el3 = read_scr_el3();
61499c2713SBiju Das 
62499c2713SBiju Das 	write_scr_el3(scr_el3 | SCR_IRQ_BIT);
63499c2713SBiju Das 	dsb();
64499c2713SBiju Das 	wfi();
65499c2713SBiju Das 	write_scr_el3(scr_el3);
66499c2713SBiju Das }
67499c2713SBiju Das 
68499c2713SBiju Das static int rcar_pwr_domain_on(u_register_t mpidr)
69499c2713SBiju Das {
70499c2713SBiju Das 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
71499c2713SBiju Das 	rcar_pwrc_cpuon(mpidr);
72499c2713SBiju Das 
73499c2713SBiju Das 	return PSCI_E_SUCCESS;
74499c2713SBiju Das }
75499c2713SBiju Das 
76499c2713SBiju Das static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
77499c2713SBiju Das {
78499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
79499c2713SBiju Das 	unsigned long mpidr = read_mpidr_el1();
80499c2713SBiju Das 
81499c2713SBiju Das 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
82499c2713SBiju Das 		if (cluster_type == RCAR_CLUSTER_A53A57)
83499c2713SBiju Das 			plat_cci_enable();
84499c2713SBiju Das 
85499c2713SBiju Das 	rcar_pwrc_disable_interrupt_wakeup(mpidr);
86499c2713SBiju Das 	rcar_program_mailbox(mpidr, 0);
87499c2713SBiju Das 
88499c2713SBiju Das 	gicv2_cpuif_enable();
89499c2713SBiju Das 	gicv2_pcpu_distif_init();
90499c2713SBiju Das }
91499c2713SBiju Das 
92499c2713SBiju Das static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
93499c2713SBiju Das {
94499c2713SBiju Das #if RCAR_LSI != RCAR_D3
95499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
96499c2713SBiju Das #endif
97499c2713SBiju Das 	unsigned long mpidr = read_mpidr_el1();
98499c2713SBiju Das 
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 #if RCAR_SYSTEM_SUSPEND
133499c2713SBiju Das 	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
134499c2713SBiju Das 		rcar_pwrc_suspend_to_ram();
135499c2713SBiju Das #endif
136499c2713SBiju Das }
137499c2713SBiju Das 
138499c2713SBiju Das static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
139499c2713SBiju Das 					   *target_state)
140499c2713SBiju Das {
141499c2713SBiju Das 	uint32_t cluster_type = rcar_pwrc_get_cluster();
142499c2713SBiju Das 
143499c2713SBiju Das 	if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
144499c2713SBiju Das 		goto finish;
145499c2713SBiju Das 
146499c2713SBiju Das 	plat_rcar_gic_driver_init();
147499c2713SBiju Das 	plat_rcar_gic_init();
148499c2713SBiju Das 
149499c2713SBiju Das 	if (cluster_type == RCAR_CLUSTER_A53A57)
150499c2713SBiju Das 		plat_cci_init();
151499c2713SBiju Das 
152499c2713SBiju Das 	rcar_pwrc_restore_timer_state();
153499c2713SBiju Das 	rcar_pwrc_setup();
154499c2713SBiju Das 	rcar_pwrc_code_copy_to_system_ram();
155499c2713SBiju Das 
156499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
157499c2713SBiju Das 	rcar_pwrc_init_suspend_to_ram();
158499c2713SBiju Das #endif
159499c2713SBiju Das finish:
160499c2713SBiju Das 	rcar_pwr_domain_on_finish(target_state);
161499c2713SBiju Das }
162499c2713SBiju Das 
163499c2713SBiju Das static void __dead2 rcar_system_off(void)
164499c2713SBiju Das {
165499c2713SBiju Das #if PMIC_ROHM_BD9571
166499c2713SBiju Das #if PMIC_LEVEL_MODE
167499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
168499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
169499c2713SBiju Das #else
170499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
171499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
172499c2713SBiju Das #endif
173499c2713SBiju Das #else
174499c2713SBiju Das 	uint64_t cpu = read_mpidr_el1() & 0x0000ffff;
175499c2713SBiju Das 	int32_t rtn_on;
176499c2713SBiju Das 
177499c2713SBiju Das 	rtn_on = rcar_pwrc_cpu_on_check(cpu);
178499c2713SBiju Das 
179499c2713SBiju Das 	if (cpu == rcar_boot_mpidr)
180499c2713SBiju Das 		panic();
181499c2713SBiju Das 
182499c2713SBiju Das 	if (rtn_on)
183499c2713SBiju Das 		panic();
184499c2713SBiju Das 
185499c2713SBiju Das 	rcar_pwrc_cpuoff(cpu);
186499c2713SBiju Das 	rcar_pwrc_clusteroff(cpu);
187499c2713SBiju Das 
188499c2713SBiju Das #endif /* PMIC_ROHM_BD9571 */
189499c2713SBiju Das 	wfi();
190499c2713SBiju Das 	ERROR("RCAR System Off: operation not handled.\n");
191499c2713SBiju Das 	panic();
192499c2713SBiju Das }
193499c2713SBiju Das 
194499c2713SBiju Das static void __dead2 rcar_system_reset(void)
195499c2713SBiju Das {
196499c2713SBiju Das #if PMIC_ROHM_BD9571
197499c2713SBiju Das #if PMIC_LEVEL_MODE
198499c2713SBiju Das #if RCAR_SYSTEM_RESET_KEEPON_DDR
199499c2713SBiju Das 	uint8_t mode;
200499c2713SBiju Das 	int32_t error;
201499c2713SBiju Das 
202499c2713SBiju Das 	error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
203499c2713SBiju Das 	if (error) {
204499c2713SBiju Das 		ERROR("Failed send KEEP10 magic ret=%d\n", error);
205499c2713SBiju Das 		goto done;
206499c2713SBiju Das 	}
207499c2713SBiju Das 
208499c2713SBiju Das 	error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
209499c2713SBiju Das 	if (error) {
210499c2713SBiju Das 		ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error);
211499c2713SBiju Das 		goto done;
212499c2713SBiju Das 	}
213499c2713SBiju Das 
214499c2713SBiju Das 	mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
215499c2713SBiju Das 	error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
216499c2713SBiju Das 	if (error) {
217499c2713SBiju Das 		ERROR("Failed send KEEPON_DDRx ret=%d\n", error);
218499c2713SBiju Das 		goto done;
219499c2713SBiju Das 	}
220499c2713SBiju Das 
221499c2713SBiju Das 	rcar_pwrc_set_suspend_to_ram();
222499c2713SBiju Das done:
223499c2713SBiju Das #else
224499c2713SBiju Das 	if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
225499c2713SBiju Das 		ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
226499c2713SBiju Das #endif
227499c2713SBiju Das #else
228499c2713SBiju Das #if (RCAR_GEN3_ULCB == 1)
229499c2713SBiju Das 	rcar_cpld_reset_cpu();
230499c2713SBiju Das #endif
231499c2713SBiju Das #endif
232499c2713SBiju Das #else
233499c2713SBiju Das 	rcar_pwrc_system_reset();
234499c2713SBiju Das #endif
235499c2713SBiju Das 	wfi();
236499c2713SBiju Das 
237499c2713SBiju Das 	ERROR("RCAR System Reset: operation not handled.\n");
238499c2713SBiju Das 	panic();
239499c2713SBiju Das }
240499c2713SBiju Das 
241499c2713SBiju Das static int rcar_validate_power_state(unsigned int power_state,
242499c2713SBiju Das 				    psci_power_state_t *req_state)
243499c2713SBiju Das {
244499c2713SBiju Das 	unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
245499c2713SBiju Das 	unsigned int pstate = psci_get_pstate_type(power_state);
246499c2713SBiju Das 	uint32_t i;
247499c2713SBiju Das 
248499c2713SBiju Das 	if (pstate == PSTATE_TYPE_STANDBY) {
249499c2713SBiju Das 		if (pwr_lvl != MPIDR_AFFLVL0)
250499c2713SBiju Das 			return PSCI_E_INVALID_PARAMS;
251499c2713SBiju Das 
252499c2713SBiju Das 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
253499c2713SBiju Das 	} else {
254499c2713SBiju Das 		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
255499c2713SBiju Das 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
256499c2713SBiju Das 	}
257499c2713SBiju Das 
258499c2713SBiju Das 	if (psci_get_pstate_id(power_state))
259499c2713SBiju Das 		return PSCI_E_INVALID_PARAMS;
260499c2713SBiju Das 
261499c2713SBiju Das 	return PSCI_E_SUCCESS;
262499c2713SBiju Das }
263499c2713SBiju Das 
264499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
265499c2713SBiju Das static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
266499c2713SBiju Das {
267499c2713SBiju Das 	unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU;
268499c2713SBiju Das 	int i;
269499c2713SBiju Das 
270499c2713SBiju Das 	if (mpidr != rcar_boot_mpidr)
271499c2713SBiju Das 		goto deny;
272499c2713SBiju Das 
273499c2713SBiju Das 	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
274499c2713SBiju Das 		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
275499c2713SBiju Das 
276499c2713SBiju Das 	return;
277499c2713SBiju Das deny:
278499c2713SBiju Das 	/* deny system suspend entry */
279499c2713SBiju Das 	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
280499c2713SBiju Das 	for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
281499c2713SBiju Das 		req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
282499c2713SBiju Das }
283499c2713SBiju Das #endif
284499c2713SBiju Das 
285499c2713SBiju Das static const plat_psci_ops_t rcar_plat_psci_ops = {
286499c2713SBiju Das 	.cpu_standby			= rcar_cpu_standby,
287499c2713SBiju Das 	.pwr_domain_on			= rcar_pwr_domain_on,
288499c2713SBiju Das 	.pwr_domain_off			= rcar_pwr_domain_off,
289499c2713SBiju Das 	.pwr_domain_suspend		= rcar_pwr_domain_suspend,
290499c2713SBiju Das 	.pwr_domain_on_finish		= rcar_pwr_domain_on_finish,
291499c2713SBiju Das 	.pwr_domain_suspend_finish	= rcar_pwr_domain_suspend_finish,
292499c2713SBiju Das 	.system_off			= rcar_system_off,
293499c2713SBiju Das 	.system_reset			= rcar_system_reset,
294499c2713SBiju Das 	.validate_power_state		= rcar_validate_power_state,
295499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
296499c2713SBiju Das 	.get_sys_suspend_power_state	= rcar_get_sys_suspend_power_state,
297499c2713SBiju Das #endif
298499c2713SBiju Das };
299499c2713SBiju Das 
300499c2713SBiju Das int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
301499c2713SBiju Das {
302499c2713SBiju Das 	*psci_ops = &rcar_plat_psci_ops;
303499c2713SBiju Das 	rcar_sec_entrypoint = sec_entrypoint;
304499c2713SBiju Das 
305499c2713SBiju Das #if RCAR_SYSTEM_SUSPEND
306499c2713SBiju Das 	rcar_pwrc_init_suspend_to_ram();
307499c2713SBiju Das #endif
308499c2713SBiju Das 	return 0;
309499c2713SBiju Das }
310499c2713SBiju Das 
311