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