blob: 6fc47b95c4377bfeb33bfd8ee11f8d0cf21ab157 [file] [log] [blame]
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +02001/*
Louis Mayencourt1c819c32020-01-24 13:30:28 +00002 * Copyright (c) 2015-2020, 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
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +02009#include <platform_def.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
11#include <arch_helpers.h>
12#include <common/bl_common.h>
13#include <common/debug.h>
14#include <drivers/arm/cci.h>
15#include <drivers/arm/gicv2.h>
16#include <lib/bakery_lock.h>
17#include <lib/mmio.h>
18#include <lib/psci/psci.h>
19#include <plat/common/platform.h>
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020020
21#include "iic_dvfs.h"
22#include "pwrc.h"
23#include "rcar_def.h"
24#include "rcar_private.h"
Marek Vasut38ec9e52018-12-28 11:26:03 +010025#include "ulcb_cpld.h"
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020026
27#define DVFS_SET_VID_0V (0x00)
28#define P_ALL_OFF (0x80)
29#define KEEPON_DDR1C (0x08)
30#define KEEPON_DDR0C (0x04)
31#define KEEPON_DDR1 (0x02)
32#define KEEPON_DDR0 (0x01)
33
34#define SYSTEM_PWR_STATE(s) ((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
35#define CLUSTER_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL1])
36#define CORE_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL0])
37
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020038extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
39extern void plat_rcar_gic_driver_init(void);
40extern void plat_rcar_gic_init(void);
41extern u_register_t rcar_boot_mpidr;
42
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020043static uintptr_t rcar_sec_entrypoint;
44
45static void rcar_program_mailbox(uint64_t mpidr, uint64_t address)
46{
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();
78 unsigned long mpidr = read_mpidr_el1();
79
80 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
81 if (cluster_type == RCAR_CLUSTER_A53A57)
82 plat_cci_enable();
83
84 rcar_pwrc_disable_interrupt_wakeup(mpidr);
85 rcar_program_mailbox(mpidr, 0);
86
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
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020096 unsigned long mpidr = read_mpidr_el1();
97
98 gicv2_cpuif_disable();
99 rcar_pwrc_cpuoff(mpidr);
100
Marek Vasut4ae342c2019-01-05 13:56:03 +0100101#if RCAR_LSI != RCAR_D3
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200102 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
103 if (cluster_type == RCAR_CLUSTER_A53A57)
104 plat_cci_disable();
105
106 rcar_pwrc_clusteroff(mpidr);
107 }
Marek Vasut4ae342c2019-01-05 13:56:03 +0100108#endif
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200109}
110
111static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
112{
113 uint32_t cluster_type = rcar_pwrc_get_cluster();
114 unsigned long mpidr = read_mpidr_el1();
115
116 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
117 return;
118
119 rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
120 rcar_pwrc_enable_interrupt_wakeup(mpidr);
121 gicv2_cpuif_disable();
122 rcar_pwrc_cpuoff(mpidr);
123
124 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
125 if (cluster_type == RCAR_CLUSTER_A53A57)
126 plat_cci_disable();
127
128 rcar_pwrc_clusteroff(mpidr);
129 }
130
131#if RCAR_SYSTEM_SUSPEND
132 if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
133 rcar_pwrc_suspend_to_ram();
134#endif
135}
136
137static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
138 *target_state)
139{
140 uint32_t cluster_type = rcar_pwrc_get_cluster();
141
142 if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
143 goto finish;
144
145 plat_rcar_gic_driver_init();
146 plat_rcar_gic_init();
147
148 if (cluster_type == RCAR_CLUSTER_A53A57)
149 plat_cci_init();
150
Toshiyuki Ogasaharab67a8ca2019-03-22 16:14:00 +0900151 rcar_pwrc_restore_timer_state();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200152 rcar_pwrc_setup();
Marek Vasute7246492018-12-31 17:12:45 +0100153 rcar_pwrc_code_copy_to_system_ram();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200154
155#if RCAR_SYSTEM_SUSPEND
156 rcar_pwrc_init_suspend_to_ram();
157#endif
158finish:
159 rcar_pwr_domain_on_finish(target_state);
160}
161
162static void __dead2 rcar_system_off(void)
163{
164#if PMIC_ROHM_BD9571
165#if PMIC_LEVEL_MODE
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200166 if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
167 ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
168#else
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200169 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
170 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
171#endif
172#else
173 uint64_t cpu = read_mpidr_el1() & 0x0000ffff;
174 int32_t rtn_on;
175
Marek Vasut122555f2019-01-05 16:21:14 +0100176 rtn_on = rcar_pwrc_cpu_on_check(cpu);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200177
178 if (cpu == rcar_boot_mpidr)
179 panic();
180
181 if (rtn_on)
182 panic();
183
184 rcar_pwrc_cpuoff(cpu);
185 rcar_pwrc_clusteroff(cpu);
186
187#endif /* PMIC_ROHM_BD9571 */
188 wfi();
189 ERROR("RCAR System Off: operation not handled.\n");
190 panic();
191}
192
193static void __dead2 rcar_system_reset(void)
194{
195#if PMIC_ROHM_BD9571
196#if PMIC_LEVEL_MODE
197#if RCAR_SYSTEM_RESET_KEEPON_DDR
198 uint8_t mode;
199 int32_t error;
200
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200201 error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
202 if (error) {
203 ERROR("Failed send KEEP10 magic ret=%d \n", error);
204 goto done;
205 }
206
207 error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
208 if (error) {
209 ERROR("Failed recieve BKUP_Mode_Cnt ret=%d \n", error);
210 goto done;
211 }
212
213 mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
214 error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
215 if (error) {
216 ERROR("Failed send KEEPON_DDRx ret=%d \n", error);
217 goto done;
218 }
219
220 rcar_pwrc_set_suspend_to_ram();
221done:
222#else
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200223 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
224 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
225#endif
226#else
227#if (RCAR_GEN3_ULCB == 1)
228 rcar_cpld_reset_cpu();
229#endif
230#endif
231#else
232 rcar_pwrc_system_reset();
233#endif
234 wfi();
235
236 ERROR("RCAR System Reset: operation not handled.\n");
237 panic();
238}
239
240static int rcar_validate_power_state(unsigned int power_state,
241 psci_power_state_t *req_state)
242{
243 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
244 unsigned int pstate = psci_get_pstate_type(power_state);
245 uint32_t i;
246
247 if (pstate == PSTATE_TYPE_STANDBY) {
248 if (pwr_lvl != MPIDR_AFFLVL0)
249 return PSCI_E_INVALID_PARAMS;
250
251 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
252 } else {
253 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
254 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
255 }
256
257 if (psci_get_pstate_id(power_state))
258 return PSCI_E_INVALID_PARAMS;
259
260 return PSCI_E_SUCCESS;
261}
262
263#if RCAR_SYSTEM_SUSPEND
264static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
265{
266 unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU;
267 int i;
268
269 if (mpidr != rcar_boot_mpidr)
270 goto deny;
271
272 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
273 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
274
275 return;
276deny:
277 /* deny system suspend entry */
278 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
279 for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
280 req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
281}
282#endif
283
284static const plat_psci_ops_t rcar_plat_psci_ops = {
285 .cpu_standby = rcar_cpu_standby,
286 .pwr_domain_on = rcar_pwr_domain_on,
287 .pwr_domain_off = rcar_pwr_domain_off,
288 .pwr_domain_suspend = rcar_pwr_domain_suspend,
289 .pwr_domain_on_finish = rcar_pwr_domain_on_finish,
290 .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish,
291 .system_off = rcar_system_off,
292 .system_reset = rcar_system_reset,
293 .validate_power_state = rcar_validate_power_state,
294#if RCAR_SYSTEM_SUSPEND
295 .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state,
296#endif
297};
298
299int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
300{
301 *psci_ops = &rcar_plat_psci_ops;
302 rcar_sec_entrypoint = sec_entrypoint;
303
304#if RCAR_SYSTEM_SUSPEND
305 rcar_pwrc_init_suspend_to_ram();
306#endif
307 return 0;
308}
309