blob: dbf3ac54ded5b6b65251db734b7980b867f5c644 [file] [log] [blame]
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +02001/*
2 * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved.
3 *
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"
25
26#define DVFS_SET_VID_0V (0x00)
27#define P_ALL_OFF (0x80)
28#define KEEPON_DDR1C (0x08)
29#define KEEPON_DDR0C (0x04)
30#define KEEPON_DDR1 (0x02)
31#define KEEPON_DDR0 (0x01)
32
33#define SYSTEM_PWR_STATE(s) ((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
34#define CLUSTER_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL1])
35#define CORE_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL0])
36
37uint64_t rcar_stack_generic_timer[5] __attribute__ ((section("data")));
38
39extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
40extern void plat_rcar_gic_driver_init(void);
41extern void plat_rcar_gic_init(void);
42extern u_register_t rcar_boot_mpidr;
43
44#if (RCAR_GEN3_ULCB == 1)
45extern void rcar_cpld_reset_cpu(void);
46#endif
47
48static uintptr_t rcar_sec_entrypoint;
49
50static void rcar_program_mailbox(uint64_t mpidr, uint64_t address)
51{
52 mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE;
53 uint64_t linear_id = plat_core_pos_by_mpidr(mpidr);
54 unsigned long range;
55
56 rcar_mboxes[linear_id].value = address;
57 range = (unsigned long)&rcar_mboxes[linear_id];
58
59 flush_dcache_range(range, sizeof(range));
60}
61
62static void rcar_cpu_standby(plat_local_state_t cpu_state)
63{
64 uint32_t scr_el3 = read_scr_el3();
65
66 write_scr_el3(scr_el3 | SCR_IRQ_BIT);
67 dsb();
68 wfi();
69 write_scr_el3(scr_el3);
70}
71
72static int rcar_pwr_domain_on(u_register_t mpidr)
73{
74 rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
75 rcar_pwrc_cpuon(mpidr);
76
77 return PSCI_E_SUCCESS;
78}
79
80static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
81{
82 uint32_t cluster_type = rcar_pwrc_get_cluster();
83 unsigned long mpidr = read_mpidr_el1();
84
85 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
86 if (cluster_type == RCAR_CLUSTER_A53A57)
87 plat_cci_enable();
88
89 rcar_pwrc_disable_interrupt_wakeup(mpidr);
90 rcar_program_mailbox(mpidr, 0);
91
92 gicv2_cpuif_enable();
93 gicv2_pcpu_distif_init();
94}
95
96static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
97{
98 uint32_t cluster_type = rcar_pwrc_get_cluster();
99 unsigned long mpidr = read_mpidr_el1();
100
101 gicv2_cpuif_disable();
102 rcar_pwrc_cpuoff(mpidr);
103
104 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
105 if (cluster_type == RCAR_CLUSTER_A53A57)
106 plat_cci_disable();
107
108 rcar_pwrc_clusteroff(mpidr);
109 }
110}
111
112static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
113{
114 uint32_t cluster_type = rcar_pwrc_get_cluster();
115 unsigned long mpidr = read_mpidr_el1();
116
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 }
131
132#if RCAR_SYSTEM_SUSPEND
133 if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
134 rcar_pwrc_suspend_to_ram();
135#endif
136}
137
138static void rcar_pwr_domain_suspend_finish(const psci_power_state_t
139 *target_state)
140{
141 uint32_t cluster_type = rcar_pwrc_get_cluster();
142
143 if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
144 goto finish;
145
146 plat_rcar_gic_driver_init();
147 plat_rcar_gic_init();
148
149 if (cluster_type == RCAR_CLUSTER_A53A57)
150 plat_cci_init();
151
152 rcar_pwrc_restore_generic_timer(rcar_stack_generic_timer);
153
154 /* start generic timer */
155 write_cntfrq_el0(plat_get_syscnt_freq2());
156 mmio_write_32(RCAR_CNTC_BASE + CNTCR_OFF, CNTCR_FCREQ(U(0)) | CNTCR_EN);
157 rcar_pwrc_setup();
Marek Vasute7246492018-12-31 17:12:45 +0100158 rcar_pwrc_code_copy_to_system_ram();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200159
160#if RCAR_SYSTEM_SUSPEND
161 rcar_pwrc_init_suspend_to_ram();
162#endif
163finish:
164 rcar_pwr_domain_on_finish(target_state);
165}
166
167static void __dead2 rcar_system_off(void)
168{
169#if PMIC_ROHM_BD9571
170#if PMIC_LEVEL_MODE
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200171 if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
172 ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
173#else
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200174 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
175 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
176#endif
177#else
178 uint64_t cpu = read_mpidr_el1() & 0x0000ffff;
179 int32_t rtn_on;
180
181 rtn_on = cpu_on_check(cpu);
182
183 if (cpu == rcar_boot_mpidr)
184 panic();
185
186 if (rtn_on)
187 panic();
188
189 rcar_pwrc_cpuoff(cpu);
190 rcar_pwrc_clusteroff(cpu);
191
192#endif /* PMIC_ROHM_BD9571 */
193 wfi();
194 ERROR("RCAR System Off: operation not handled.\n");
195 panic();
196}
197
198static void __dead2 rcar_system_reset(void)
199{
200#if PMIC_ROHM_BD9571
201#if PMIC_LEVEL_MODE
202#if RCAR_SYSTEM_RESET_KEEPON_DDR
203 uint8_t mode;
204 int32_t error;
205
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200206 error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
207 if (error) {
208 ERROR("Failed send KEEP10 magic ret=%d \n", error);
209 goto done;
210 }
211
212 error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
213 if (error) {
214 ERROR("Failed recieve BKUP_Mode_Cnt ret=%d \n", error);
215 goto done;
216 }
217
218 mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
219 error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
220 if (error) {
221 ERROR("Failed send KEEPON_DDRx ret=%d \n", error);
222 goto done;
223 }
224
225 rcar_pwrc_set_suspend_to_ram();
226done:
227#else
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200228 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
229 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
230#endif
231#else
232#if (RCAR_GEN3_ULCB == 1)
233 rcar_cpld_reset_cpu();
234#endif
235#endif
236#else
237 rcar_pwrc_system_reset();
238#endif
239 wfi();
240
241 ERROR("RCAR System Reset: operation not handled.\n");
242 panic();
243}
244
245static int rcar_validate_power_state(unsigned int power_state,
246 psci_power_state_t *req_state)
247{
248 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
249 unsigned int pstate = psci_get_pstate_type(power_state);
250 uint32_t i;
251
252 if (pstate == PSTATE_TYPE_STANDBY) {
253 if (pwr_lvl != MPIDR_AFFLVL0)
254 return PSCI_E_INVALID_PARAMS;
255
256 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
257 } else {
258 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
259 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
260 }
261
262 if (psci_get_pstate_id(power_state))
263 return PSCI_E_INVALID_PARAMS;
264
265 return PSCI_E_SUCCESS;
266}
267
268#if RCAR_SYSTEM_SUSPEND
269static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
270{
271 unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU;
272 int i;
273
274 if (mpidr != rcar_boot_mpidr)
275 goto deny;
276
277 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
278 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
279
280 return;
281deny:
282 /* deny system suspend entry */
283 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
284 for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
285 req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
286}
287#endif
288
289static const plat_psci_ops_t rcar_plat_psci_ops = {
290 .cpu_standby = rcar_cpu_standby,
291 .pwr_domain_on = rcar_pwr_domain_on,
292 .pwr_domain_off = rcar_pwr_domain_off,
293 .pwr_domain_suspend = rcar_pwr_domain_suspend,
294 .pwr_domain_on_finish = rcar_pwr_domain_on_finish,
295 .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish,
296 .system_off = rcar_system_off,
297 .system_reset = rcar_system_reset,
298 .validate_power_state = rcar_validate_power_state,
299#if RCAR_SYSTEM_SUSPEND
300 .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state,
301#endif
302};
303
304int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
305{
306 *psci_ops = &rcar_plat_psci_ops;
307 rcar_sec_entrypoint = sec_entrypoint;
308
309#if RCAR_SYSTEM_SUSPEND
310 rcar_pwrc_init_suspend_to_ram();
311#endif
312 return 0;
313}
314