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