xref: /rk3399_ARM-atf/plat/renesas/rcar_gen4/plat_pm.c (revision 3c57f96aa1adb070e3ed25c230482c4e03fae345)
1b45b5bacSMarek Vasut /*
2b45b5bacSMarek Vasut  * Copyright (c) 2015-2025, Renesas Electronics Corporation. All rights reserved.
3b45b5bacSMarek Vasut  *
4b45b5bacSMarek Vasut  * SPDX-License-Identifier: BSD-3-Clause
5b45b5bacSMarek Vasut  */
6b45b5bacSMarek Vasut 
7b45b5bacSMarek Vasut #include <errno.h>
8b45b5bacSMarek Vasut 
9b45b5bacSMarek Vasut #include <arch_helpers.h>
10b45b5bacSMarek Vasut #include <common/bl_common.h>
11b45b5bacSMarek Vasut #include <common/debug.h>
12b45b5bacSMarek Vasut #include <drivers/arm/cci.h>
13b45b5bacSMarek Vasut #include <drivers/arm/gicv3.h>
14b45b5bacSMarek Vasut #include <lib/bakery_lock.h>
15b45b5bacSMarek Vasut #include <lib/mmio.h>
16b45b5bacSMarek Vasut #include <lib/psci/psci.h>
17b45b5bacSMarek Vasut #include <plat/common/platform.h>
18b45b5bacSMarek Vasut #include "pwrc.h"
19b45b5bacSMarek Vasut 
20b45b5bacSMarek Vasut #include "platform_def.h"
21b45b5bacSMarek Vasut #include "rcar_def.h"
22b45b5bacSMarek Vasut #include "rcar_private.h"
23b45b5bacSMarek Vasut 
24b45b5bacSMarek Vasut #define SYSTEM_PWR_STATE(s)	((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
25b45b5bacSMarek Vasut #define CLUSTER_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL1])
26b45b5bacSMarek Vasut #define CORE_PWR_STATE(s)	((s)->pwr_domain_state[MPIDR_AFFLVL0])
27b45b5bacSMarek Vasut 
28b45b5bacSMarek Vasut static uintptr_t rcar_sec_entrypoint;
29b45b5bacSMarek Vasut static gicv3_redist_ctx_t rdist_ctx[PLATFORM_CORE_COUNT];
30b45b5bacSMarek Vasut static gicv3_dist_ctx_t dist_ctx;
31b45b5bacSMarek Vasut 
32b45b5bacSMarek Vasut static void rcar_program_mailbox(u_register_t mpidr, uintptr_t address)
33b45b5bacSMarek Vasut {
34b45b5bacSMarek Vasut 	const int linear_id = plat_core_pos_by_mpidr(mpidr);
35b45b5bacSMarek Vasut 	void *mbox_addr = (void *)MBOX_BASE + (CACHE_WRITEBACK_GRANULE * linear_id);
36b45b5bacSMarek Vasut 	uint64_t *value = (uint64_t *)mbox_addr;
37b45b5bacSMarek Vasut 
38b45b5bacSMarek Vasut 	if (linear_id < 0) {
39b45b5bacSMarek Vasut 		ERROR("BL3-1 : The value of passed MPIDR is invalid.");
40b45b5bacSMarek Vasut 		panic();
41b45b5bacSMarek Vasut 	}
42b45b5bacSMarek Vasut 
43b45b5bacSMarek Vasut 	*value = address;
44b45b5bacSMarek Vasut 
45b45b5bacSMarek Vasut 	flush_dcache_range((uintptr_t)value, CACHE_WRITEBACK_GRANULE);
46b45b5bacSMarek Vasut }
47b45b5bacSMarek Vasut 
48b45b5bacSMarek Vasut static void rcar_cpu_standby(plat_local_state_t cpu_state)
49b45b5bacSMarek Vasut {
50b45b5bacSMarek Vasut 	u_register_t scr_el3 = read_scr_el3();
51b45b5bacSMarek Vasut 
52b45b5bacSMarek Vasut 	write_scr_el3(scr_el3 | SCR_IRQ_BIT);
53b45b5bacSMarek Vasut 	dsb();
54b45b5bacSMarek Vasut 	wfi();
55b45b5bacSMarek Vasut 	write_scr_el3(scr_el3);
56b45b5bacSMarek Vasut }
57b45b5bacSMarek Vasut 
58b45b5bacSMarek Vasut static int rcar_pwr_domain_on(u_register_t mpidr)
59b45b5bacSMarek Vasut {
60b45b5bacSMarek Vasut 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
61b45b5bacSMarek Vasut 	rcar_pwrc_cpuon(mpidr);
62b45b5bacSMarek Vasut 
63b45b5bacSMarek Vasut 	return PSCI_E_SUCCESS;
64b45b5bacSMarek Vasut }
65b45b5bacSMarek Vasut 
66b45b5bacSMarek Vasut static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
67b45b5bacSMarek Vasut {
68b45b5bacSMarek Vasut 	u_register_t mpidr = read_mpidr_el1();
69b45b5bacSMarek Vasut 
70b45b5bacSMarek Vasut 	rcar_pwrc_disable_interrupt_wakeup(mpidr);
71b45b5bacSMarek Vasut 	rcar_program_mailbox(mpidr, 0U);
72b45b5bacSMarek Vasut }
73b45b5bacSMarek Vasut 
74b45b5bacSMarek Vasut static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
75b45b5bacSMarek Vasut {
76b45b5bacSMarek Vasut 	u_register_t mpidr = read_mpidr_el1();
77b45b5bacSMarek Vasut 
78b45b5bacSMarek Vasut 	rcar_pwrc_disable_interrupt_wakeup(mpidr);
79b45b5bacSMarek Vasut 
80b45b5bacSMarek Vasut 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
81b45b5bacSMarek Vasut 		rcar_pwrc_clusteroff(mpidr);
82b45b5bacSMarek Vasut 	} else {
83b45b5bacSMarek Vasut 		rcar_pwrc_cpuoff(mpidr);
84b45b5bacSMarek Vasut 	}
85b45b5bacSMarek Vasut }
86b45b5bacSMarek Vasut 
87b45b5bacSMarek Vasut static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
88b45b5bacSMarek Vasut {
89b45b5bacSMarek Vasut 	u_register_t mpidr = read_mpidr_el1();
90b45b5bacSMarek Vasut 
91b45b5bacSMarek Vasut 	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) {
92b45b5bacSMarek Vasut 		return;
93b45b5bacSMarek Vasut 	}
94b45b5bacSMarek Vasut 
95b45b5bacSMarek Vasut 	rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
96b45b5bacSMarek Vasut 	rcar_pwrc_enable_interrupt_wakeup(mpidr);
97b45b5bacSMarek Vasut 
98b45b5bacSMarek Vasut 	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
99b45b5bacSMarek Vasut 		for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++)
100b45b5bacSMarek Vasut 			gicv3_rdistif_save(i, &rdist_ctx[i]);
101b45b5bacSMarek Vasut 		gicv3_distif_save(&dist_ctx);
102b45b5bacSMarek Vasut 	}
103b45b5bacSMarek Vasut 
104b45b5bacSMarek Vasut 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
105b45b5bacSMarek Vasut 		rcar_pwrc_clusteroff(mpidr);
106b45b5bacSMarek Vasut 	} else {
107b45b5bacSMarek Vasut 		rcar_pwrc_cpuoff(mpidr);
108b45b5bacSMarek Vasut 	}
109b45b5bacSMarek Vasut }
110b45b5bacSMarek Vasut 
111b45b5bacSMarek Vasut static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
112b45b5bacSMarek Vasut 					   *target_state)
113b45b5bacSMarek Vasut {
114b45b5bacSMarek Vasut 	u_register_t mpidr = read_mpidr_el1();
115b45b5bacSMarek Vasut 
116b45b5bacSMarek Vasut 	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
117b45b5bacSMarek Vasut 		rcar_pwrc_restore_timer_state();
118b45b5bacSMarek Vasut 		rcar_pwrc_setup();
119b45b5bacSMarek Vasut 	}
120b45b5bacSMarek Vasut 
121b45b5bacSMarek Vasut 	rcar_pwrc_disable_interrupt_wakeup(mpidr);
122b45b5bacSMarek Vasut 	rcar_program_mailbox(mpidr, 0U);
123b45b5bacSMarek Vasut 	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
124b45b5bacSMarek Vasut 		gicv3_distif_init_restore(&dist_ctx);
125b45b5bacSMarek Vasut 		for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++)
126b45b5bacSMarek Vasut 			gicv3_rdistif_init_restore(i, &rdist_ctx[i]);
127b45b5bacSMarek Vasut 	}
128b45b5bacSMarek Vasut }
129b45b5bacSMarek Vasut 
130b45b5bacSMarek Vasut static void rcar_system_off(void)
131b45b5bacSMarek Vasut {
132b45b5bacSMarek Vasut 	u_register_t mpidr = read_mpidr_el1();
133b45b5bacSMarek Vasut 	uint32_t rtn_on;
134b45b5bacSMarek Vasut 
135b45b5bacSMarek Vasut 	if (!rcar_pwrc_mpidr_is_boot_cpu(mpidr))
136b45b5bacSMarek Vasut 		panic();
137b45b5bacSMarek Vasut 
138b45b5bacSMarek Vasut 	rtn_on = rcar_pwrc_cpu_on_check(mpidr);
139b45b5bacSMarek Vasut 
140b45b5bacSMarek Vasut 	if (rtn_on > 0U)
141b45b5bacSMarek Vasut 		panic();
142b45b5bacSMarek Vasut 
143b45b5bacSMarek Vasut 	rcar_pwrc_clusteroff(mpidr);
144b45b5bacSMarek Vasut }
145b45b5bacSMarek Vasut 
146b45b5bacSMarek Vasut static void rcar_system_reset(void)
147b45b5bacSMarek Vasut {
148*3c57f96aSMarek Vasut 	mmio_write_32(RCAR_SRESCR, 0x5AA50000U | BIT(15));
149b45b5bacSMarek Vasut }
150b45b5bacSMarek Vasut 
151b45b5bacSMarek Vasut static void rcar_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
152b45b5bacSMarek Vasut {
153b45b5bacSMarek Vasut 	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
154b45b5bacSMarek Vasut 		rcar_pwrc_suspend_to_ram();
155b45b5bacSMarek Vasut }
156b45b5bacSMarek Vasut 
157b45b5bacSMarek Vasut static int rcar_validate_power_state(unsigned int power_state,
158b45b5bacSMarek Vasut 				    psci_power_state_t *req_state)
159b45b5bacSMarek Vasut {
160b45b5bacSMarek Vasut 	uint32_t pwr_lvl = psci_get_pstate_pwrlvl(power_state);
161b45b5bacSMarek Vasut 	uint32_t pstate = psci_get_pstate_type(power_state);
162b45b5bacSMarek Vasut 	uint64_t i;
163b45b5bacSMarek Vasut 
164b45b5bacSMarek Vasut 	if (pstate == PSTATE_TYPE_STANDBY) {
165b45b5bacSMarek Vasut 		if (pwr_lvl != MPIDR_AFFLVL0)
166b45b5bacSMarek Vasut 			return PSCI_E_INVALID_PARAMS;
167b45b5bacSMarek Vasut 
168b45b5bacSMarek Vasut 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
169b45b5bacSMarek Vasut 	} else {
170b45b5bacSMarek Vasut 		for (i = MPIDR_AFFLVL0; i <= (uint64_t)pwr_lvl; i++)
171b45b5bacSMarek Vasut 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
172b45b5bacSMarek Vasut 	}
173b45b5bacSMarek Vasut 
174b45b5bacSMarek Vasut 	if (psci_get_pstate_id(power_state) != 0U)
175b45b5bacSMarek Vasut 		return PSCI_E_INVALID_PARAMS;
176b45b5bacSMarek Vasut 
177b45b5bacSMarek Vasut 	return PSCI_E_SUCCESS;
178b45b5bacSMarek Vasut }
179b45b5bacSMarek Vasut 
180b45b5bacSMarek Vasut static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
181b45b5bacSMarek Vasut {
182b45b5bacSMarek Vasut 	uint64_t i;
183b45b5bacSMarek Vasut 	u_register_t mpidr = read_mpidr_el1();
184b45b5bacSMarek Vasut 
185b45b5bacSMarek Vasut 	if (!rcar_pwrc_mpidr_is_boot_cpu(mpidr)) {
186b45b5bacSMarek Vasut 		/* deny system suspend entry */
187b45b5bacSMarek Vasut 		req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
188b45b5bacSMarek Vasut 			PSCI_LOCAL_STATE_RUN;
189b45b5bacSMarek Vasut 
190b45b5bacSMarek Vasut 		for (i = MPIDR_AFFLVL0; i < (uint64_t)PLAT_MAX_PWR_LVL; i++)
191b45b5bacSMarek Vasut 			req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
192b45b5bacSMarek Vasut 	} else {
193b45b5bacSMarek Vasut 		for (i = MPIDR_AFFLVL0; i <= (uint64_t)PLAT_MAX_PWR_LVL; i++)
194b45b5bacSMarek Vasut 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
195b45b5bacSMarek Vasut 	}
196b45b5bacSMarek Vasut }
197b45b5bacSMarek Vasut 
198b45b5bacSMarek Vasut static plat_psci_ops_t rcar_plat_psci_ops = {
199b45b5bacSMarek Vasut 	.cpu_standby			= rcar_cpu_standby,
200b45b5bacSMarek Vasut 	.pwr_domain_on			= rcar_pwr_domain_on,
201b45b5bacSMarek Vasut 	.pwr_domain_off			= rcar_pwr_domain_off,
202b45b5bacSMarek Vasut 	.pwr_domain_suspend		= rcar_pwr_domain_suspend,
203b45b5bacSMarek Vasut 	.pwr_domain_on_finish		= rcar_pwr_domain_on_finish,
204b45b5bacSMarek Vasut 	.pwr_domain_suspend_finish	= rcar_pwr_domain_suspend_finish,
205b45b5bacSMarek Vasut 	.system_off			= rcar_system_off,
206b45b5bacSMarek Vasut 	.system_reset			= rcar_system_reset,
207b45b5bacSMarek Vasut 	.validate_power_state		= rcar_validate_power_state,
208b45b5bacSMarek Vasut 	.pwr_domain_pwr_down		= rcar_pwr_domain_pwr_down_wfi,
209b45b5bacSMarek Vasut 	.get_sys_suspend_power_state	= rcar_get_sys_suspend_power_state,
210b45b5bacSMarek Vasut };
211b45b5bacSMarek Vasut 
212b45b5bacSMarek Vasut int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
213b45b5bacSMarek Vasut {
214*3c57f96aSMarek Vasut 	*psci_ops = &rcar_plat_psci_ops;
215b45b5bacSMarek Vasut 	rcar_sec_entrypoint = sec_entrypoint;
216b45b5bacSMarek Vasut 
217b45b5bacSMarek Vasut 	return 0;
218b45b5bacSMarek Vasut }
219