blob: 84cc47e0d13fe6688a022144a8234e09a3b2f6a7 [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
7#include <arch_helpers.h>
8#include <bakery_lock.h>
9#include <bl_common.h>
10#include <cci.h>
11#include <debug.h>
12#include <errno.h>
13#include <gicv2.h>
14#include <mmio.h>
15#include <platform.h>
16#include <platform_def.h>
17#include <psci.h>
18
19#include "iic_dvfs.h"
20#include "pwrc.h"
21#include "rcar_def.h"
22#include "rcar_private.h"
23
24#define DVFS_SET_VID_0V (0x00)
25#define P_ALL_OFF (0x80)
26#define KEEPON_DDR1C (0x08)
27#define KEEPON_DDR0C (0x04)
28#define KEEPON_DDR1 (0x02)
29#define KEEPON_DDR0 (0x01)
30
31#define SYSTEM_PWR_STATE(s) ((s)->pwr_domain_state[PLAT_MAX_PWR_LVL])
32#define CLUSTER_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL1])
33#define CORE_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL0])
34
35uint64_t rcar_stack_generic_timer[5] __attribute__ ((section("data")));
36
37extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
38extern void plat_rcar_gic_driver_init(void);
39extern void plat_rcar_gic_init(void);
40extern u_register_t rcar_boot_mpidr;
41
42#if (RCAR_GEN3_ULCB == 1)
43extern void rcar_cpld_reset_cpu(void);
44#endif
45
46static uintptr_t rcar_sec_entrypoint;
47
48static void rcar_program_mailbox(uint64_t mpidr, uint64_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
60static void rcar_cpu_standby(plat_local_state_t cpu_state)
61{
62 uint32_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
70static 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
78static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
79{
80 uint32_t cluster_type = rcar_pwrc_get_cluster();
81 unsigned long 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_pwrc_disable_interrupt_wakeup(mpidr);
88 rcar_program_mailbox(mpidr, 0);
89
90 gicv2_cpuif_enable();
91 gicv2_pcpu_distif_init();
92}
93
94static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
95{
96 uint32_t cluster_type = rcar_pwrc_get_cluster();
97 unsigned long mpidr = read_mpidr_el1();
98
99 gicv2_cpuif_disable();
100 rcar_pwrc_cpuoff(mpidr);
101
102 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 }
108}
109
110static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state)
111{
112 uint32_t cluster_type = rcar_pwrc_get_cluster();
113 unsigned long mpidr = read_mpidr_el1();
114
115 if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
116 return;
117
118 rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
119 rcar_pwrc_enable_interrupt_wakeup(mpidr);
120 gicv2_cpuif_disable();
121 rcar_pwrc_cpuoff(mpidr);
122
123 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
124 if (cluster_type == RCAR_CLUSTER_A53A57)
125 plat_cci_disable();
126
127 rcar_pwrc_clusteroff(mpidr);
128 }
129
130#if RCAR_SYSTEM_SUSPEND
131 if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
132 rcar_pwrc_suspend_to_ram();
133#endif
134}
135
136static 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_generic_timer(rcar_stack_generic_timer);
151
152 /* start generic timer */
153 write_cntfrq_el0(plat_get_syscnt_freq2());
154 mmio_write_32(RCAR_CNTC_BASE + CNTCR_OFF, CNTCR_FCREQ(U(0)) | CNTCR_EN);
155 rcar_pwrc_setup();
156
157#if RCAR_SYSTEM_SUSPEND
158 rcar_pwrc_init_suspend_to_ram();
159#endif
160finish:
161 rcar_pwr_domain_on_finish(target_state);
162}
163
164static void __dead2 rcar_system_off(void)
165{
166#if PMIC_ROHM_BD9571
167#if PMIC_LEVEL_MODE
168 rcar_pwrc_code_copy_to_system_ram();
169 if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
170 ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
171#else
172 rcar_pwrc_code_copy_to_system_ram();
173 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
174 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
175#endif
176#else
177 uint64_t cpu = read_mpidr_el1() & 0x0000ffff;
178 int32_t rtn_on;
179
180 rtn_on = cpu_on_check(cpu);
181
182 if (cpu == rcar_boot_mpidr)
183 panic();
184
185 if (rtn_on)
186 panic();
187
188 rcar_pwrc_cpuoff(cpu);
189 rcar_pwrc_clusteroff(cpu);
190
191#endif /* PMIC_ROHM_BD9571 */
192 wfi();
193 ERROR("RCAR System Off: operation not handled.\n");
194 panic();
195}
196
197static void __dead2 rcar_system_reset(void)
198{
199#if PMIC_ROHM_BD9571
200#if PMIC_LEVEL_MODE
201#if RCAR_SYSTEM_RESET_KEEPON_DDR
202 uint8_t mode;
203 int32_t error;
204
205 rcar_pwrc_code_copy_to_system_ram();
206 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
228 rcar_pwrc_code_copy_to_system_ram();
229 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
230 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
231#endif
232#else
233#if (RCAR_GEN3_ULCB == 1)
234 rcar_cpld_reset_cpu();
235#endif
236#endif
237#else
238 rcar_pwrc_system_reset();
239#endif
240 wfi();
241
242 ERROR("RCAR System Reset: operation not handled.\n");
243 panic();
244}
245
246static int rcar_validate_power_state(unsigned int power_state,
247 psci_power_state_t *req_state)
248{
249 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
250 unsigned int pstate = psci_get_pstate_type(power_state);
251 uint32_t i;
252
253 if (pstate == PSTATE_TYPE_STANDBY) {
254 if (pwr_lvl != MPIDR_AFFLVL0)
255 return PSCI_E_INVALID_PARAMS;
256
257 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
258 } else {
259 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
260 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
261 }
262
263 if (psci_get_pstate_id(power_state))
264 return PSCI_E_INVALID_PARAMS;
265
266 return PSCI_E_SUCCESS;
267}
268
269#if RCAR_SYSTEM_SUSPEND
270static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
271{
272 unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU;
273 int i;
274
275 if (mpidr != rcar_boot_mpidr)
276 goto deny;
277
278 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
279 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
280
281 return;
282deny:
283 /* deny system suspend entry */
284 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
285 for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
286 req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
287}
288#endif
289
290static const plat_psci_ops_t rcar_plat_psci_ops = {
291 .cpu_standby = rcar_cpu_standby,
292 .pwr_domain_on = rcar_pwr_domain_on,
293 .pwr_domain_off = rcar_pwr_domain_off,
294 .pwr_domain_suspend = rcar_pwr_domain_suspend,
295 .pwr_domain_on_finish = rcar_pwr_domain_on_finish,
296 .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish,
297 .system_off = rcar_system_off,
298 .system_reset = rcar_system_reset,
299 .validate_power_state = rcar_validate_power_state,
300#if RCAR_SYSTEM_SUSPEND
301 .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state,
302#endif
303};
304
305int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
306{
307 *psci_ops = &rcar_plat_psci_ops;
308 rcar_sec_entrypoint = sec_entrypoint;
309
310#if RCAR_SYSTEM_SUSPEND
311 rcar_pwrc_init_suspend_to_ram();
312#endif
313 return 0;
314}
315