blob: 9810596def89c4d25a2c2e461bed27dc57241cd5 [file] [log] [blame]
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +02001/*
Toshiyuki Ogasahara009b4822021-07-12 19:29:52 +09002 * Copyright (c) 2015-2021, Renesas Electronics Corporation. All rights reserved.
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +02007#include <errno.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00009#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>
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020018
19#include "iic_dvfs.h"
Biju Dasd9675d32020-12-13 20:38:44 +000020#include "platform_def.h"
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020021#include "pwrc.h"
22#include "rcar_def.h"
23#include "rcar_private.h"
Biju Dase11238e2020-12-16 11:37:27 +000024#if RCAR_GEN3_ULCB
Marek Vasut38ec9e52018-12-28 11:26:03 +010025#include "ulcb_cpld.h"
Biju Dase11238e2020-12-16 11:37:27 +000026#endif /* RCAR_GEN3_ULCB */
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020027
Biju Dasd9675d32020-12-13 20:38:44 +000028#define DVFS_SET_VID_0V (0x00)
29#define P_ALL_OFF (0x80)
30#define KEEPON_DDR1C (0x08)
31#define KEEPON_DDR0C (0x04)
32#define KEEPON_DDR1 (0x02)
33#define KEEPON_DDR0 (0x01)
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020034
35#define SYSTEM_PWR_STATE(s) ((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
36#define CLUSTER_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL1])
37#define CORE_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL0])
38
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020039extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
40extern void plat_rcar_gic_driver_init(void);
41extern void plat_rcar_gic_init(void);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020042
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020043static uintptr_t rcar_sec_entrypoint;
44
Takuya Sakata59197472021-11-02 20:30:39 +090045static void rcar_program_mailbox(u_register_t mpidr, uintptr_t address)
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020046{
47 mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE;
48 uint64_t linear_id = plat_core_pos_by_mpidr(mpidr);
49 unsigned long range;
50
51 rcar_mboxes[linear_id].value = address;
52 range = (unsigned long)&rcar_mboxes[linear_id];
53
54 flush_dcache_range(range, sizeof(range));
55}
56
57static void rcar_cpu_standby(plat_local_state_t cpu_state)
58{
Louis Mayencourt1c819c32020-01-24 13:30:28 +000059 u_register_t scr_el3 = read_scr_el3();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020060
61 write_scr_el3(scr_el3 | SCR_IRQ_BIT);
62 dsb();
63 wfi();
64 write_scr_el3(scr_el3);
65}
66
67static int rcar_pwr_domain_on(u_register_t mpidr)
68{
69 rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
70 rcar_pwrc_cpuon(mpidr);
71
72 return PSCI_E_SUCCESS;
73}
74
75static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
76{
77 uint32_t cluster_type = rcar_pwrc_get_cluster();
Takuya Sakata59197472021-11-02 20:30:39 +090078 u_register_t mpidr = read_mpidr_el1();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020079
80 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
81 if (cluster_type == RCAR_CLUSTER_A53A57)
82 plat_cci_enable();
83
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020084 rcar_program_mailbox(mpidr, 0);
Takuya Sakata0034f602021-11-02 20:30:02 +090085 rcar_pwrc_enable_interrupt_wakeup(mpidr);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020086
87 gicv2_cpuif_enable();
88 gicv2_pcpu_distif_init();
89}
90
91static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
92{
Marek Vasut4ae342c2019-01-05 13:56:03 +010093#if RCAR_LSI != RCAR_D3
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020094 uint32_t cluster_type = rcar_pwrc_get_cluster();
Marek Vasut4ae342c2019-01-05 13:56:03 +010095#endif
Takuya Sakata59197472021-11-02 20:30:39 +090096 u_register_t mpidr = read_mpidr_el1();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020097
Takuya Sakata0034f602021-11-02 20:30:02 +090098 rcar_pwrc_disable_interrupt_wakeup(mpidr);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020099 gicv2_cpuif_disable();
100 rcar_pwrc_cpuoff(mpidr);
101
Marek Vasut4ae342c2019-01-05 13:56:03 +0100102#if RCAR_LSI != RCAR_D3
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200103 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
104 if (cluster_type == RCAR_CLUSTER_A53A57)
105 plat_cci_disable();
106
107 rcar_pwrc_clusteroff(mpidr);
108 }
Marek Vasut4ae342c2019-01-05 13:56:03 +0100109#endif
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200110}
111
112static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
113{
114 uint32_t cluster_type = rcar_pwrc_get_cluster();
Takuya Sakata59197472021-11-02 20:30:39 +0900115 u_register_t mpidr = read_mpidr_el1();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200116
117 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
118 return;
119
120 rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
121 rcar_pwrc_enable_interrupt_wakeup(mpidr);
122 gicv2_cpuif_disable();
123 rcar_pwrc_cpuoff(mpidr);
124
125 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
126 if (cluster_type == RCAR_CLUSTER_A53A57)
127 plat_cci_disable();
128
129 rcar_pwrc_clusteroff(mpidr);
130 }
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200131}
132
133static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
134 *target_state)
135{
136 uint32_t cluster_type = rcar_pwrc_get_cluster();
137
138 if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
139 goto finish;
140
141 plat_rcar_gic_driver_init();
142 plat_rcar_gic_init();
143
144 if (cluster_type == RCAR_CLUSTER_A53A57)
145 plat_cci_init();
146
Toshiyuki Ogasaharab67a8ca2019-03-22 16:14:00 +0900147 rcar_pwrc_restore_timer_state();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200148 rcar_pwrc_setup();
Marek Vasute7246492018-12-31 17:12:45 +0100149 rcar_pwrc_code_copy_to_system_ram();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200150
151#if RCAR_SYSTEM_SUSPEND
152 rcar_pwrc_init_suspend_to_ram();
153#endif
154finish:
155 rcar_pwr_domain_on_finish(target_state);
156}
157
Toshiyuki Ogasahara009b4822021-07-12 19:29:52 +0900158static void __dead2 rcar_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
159{
160#if RCAR_SYSTEM_SUSPEND
161 if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
162 rcar_pwrc_suspend_to_ram();
163#endif
164 wfi();
165
166 ERROR("RCAR Power Down: operation not handled.\n");
167 panic();
168}
169
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200170static void __dead2 rcar_system_off(void)
171{
172#if PMIC_ROHM_BD9571
173#if PMIC_LEVEL_MODE
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200174 if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
175 ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
176#else
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200177 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
178 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
179#endif
180#else
Takuya Sakata3e2fc612021-12-01 13:37:02 +0900181 u_register_t mpidr = read_mpidr_el1();
182 u_register_t cpu = mpidr & 0x0000ffffU;
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200183 int32_t rtn_on;
184
Takuya Sakata3e2fc612021-12-01 13:37:02 +0900185 rtn_on = rcar_pwrc_cpu_on_check(mpidr);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200186
Takuya Sakata3e2fc612021-12-01 13:37:02 +0900187 if (cpu != rcar_boot_mpidr) {
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200188 panic();
Takuya Sakata3e2fc612021-12-01 13:37:02 +0900189 }
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200190
Takuya Sakata3e2fc612021-12-01 13:37:02 +0900191 if (rtn_on != 0) {
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200192 panic();
Takuya Sakata3e2fc612021-12-01 13:37:02 +0900193 }
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200194
Takuya Sakata3e2fc612021-12-01 13:37:02 +0900195 rcar_pwrc_cpuoff(mpidr);
196 rcar_pwrc_clusteroff(mpidr);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200197
198#endif /* PMIC_ROHM_BD9571 */
199 wfi();
200 ERROR("RCAR System Off: operation not handled.\n");
201 panic();
202}
203
204static void __dead2 rcar_system_reset(void)
205{
206#if PMIC_ROHM_BD9571
207#if PMIC_LEVEL_MODE
208#if RCAR_SYSTEM_RESET_KEEPON_DDR
209 uint8_t mode;
210 int32_t error;
211
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200212 error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
213 if (error) {
Biju Dasd9675d32020-12-13 20:38:44 +0000214 ERROR("Failed send KEEP10 magic ret=%d\n", error);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200215 goto done;
216 }
217
218 error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
219 if (error) {
Biju Dasd9675d32020-12-13 20:38:44 +0000220 ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200221 goto done;
222 }
223
224 mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
225 error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
226 if (error) {
Biju Dasd9675d32020-12-13 20:38:44 +0000227 ERROR("Failed send KEEPON_DDRx ret=%d\n", error);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200228 goto done;
229 }
230
231 rcar_pwrc_set_suspend_to_ram();
232done:
233#else
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200234 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
235 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
236#endif
237#else
238#if (RCAR_GEN3_ULCB == 1)
239 rcar_cpld_reset_cpu();
240#endif
241#endif
242#else
243 rcar_pwrc_system_reset();
244#endif
245 wfi();
246
247 ERROR("RCAR System Reset: operation not handled.\n");
248 panic();
249}
250
251static int rcar_validate_power_state(unsigned int power_state,
252 psci_power_state_t *req_state)
253{
254 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
255 unsigned int pstate = psci_get_pstate_type(power_state);
256 uint32_t i;
257
258 if (pstate == PSTATE_TYPE_STANDBY) {
259 if (pwr_lvl != MPIDR_AFFLVL0)
260 return PSCI_E_INVALID_PARAMS;
261
262 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
263 } else {
264 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
265 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
266 }
267
268 if (psci_get_pstate_id(power_state))
269 return PSCI_E_INVALID_PARAMS;
270
271 return PSCI_E_SUCCESS;
272}
273
274#if RCAR_SYSTEM_SUSPEND
275static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
276{
Takuya Sakata59197472021-11-02 20:30:39 +0900277 u_register_t mpidr = read_mpidr_el1() & 0x0000ffffU;
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200278 int i;
279
280 if (mpidr != rcar_boot_mpidr)
281 goto deny;
282
283 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
284 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
285
286 return;
287deny:
288 /* deny system suspend entry */
289 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
290 for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
291 req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
292}
293#endif
294
295static const plat_psci_ops_t rcar_plat_psci_ops = {
296 .cpu_standby = rcar_cpu_standby,
297 .pwr_domain_on = rcar_pwr_domain_on,
298 .pwr_domain_off = rcar_pwr_domain_off,
299 .pwr_domain_suspend = rcar_pwr_domain_suspend,
300 .pwr_domain_on_finish = rcar_pwr_domain_on_finish,
301 .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish,
302 .system_off = rcar_system_off,
303 .system_reset = rcar_system_reset,
304 .validate_power_state = rcar_validate_power_state,
Toshiyuki Ogasahara009b4822021-07-12 19:29:52 +0900305 .pwr_domain_pwr_down_wfi = rcar_pwr_domain_pwr_down_wfi,
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200306#if RCAR_SYSTEM_SUSPEND
Biju Dasd9675d32020-12-13 20:38:44 +0000307 .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state,
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200308#endif
309};
310
311int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
312{
313 *psci_ops = &rcar_plat_psci_ops;
314 rcar_sec_entrypoint = sec_entrypoint;
315
316#if RCAR_SYSTEM_SUSPEND
317 rcar_pwrc_init_suspend_to_ram();
318#endif
319 return 0;
320}
321