blob: 7ec78cce32784baef3045237fffd26fe8996e0c2 [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
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"
Marek Vasut38ec9e52018-12-28 11:26:03 +010024#include "ulcb_cpld.h"
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020025
Biju Dasd9675d32020-12-13 20:38:44 +000026#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)
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020032
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
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020037extern 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
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020042static uintptr_t rcar_sec_entrypoint;
43
44static void rcar_program_mailbox(uint64_t mpidr, uint64_t address)
45{
46 mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE;
47 uint64_t linear_id = plat_core_pos_by_mpidr(mpidr);
48 unsigned long range;
49
50 rcar_mboxes[linear_id].value = address;
51 range = (unsigned long)&rcar_mboxes[linear_id];
52
53 flush_dcache_range(range, sizeof(range));
54}
55
56static void rcar_cpu_standby(plat_local_state_t cpu_state)
57{
Louis Mayencourt1c819c32020-01-24 13:30:28 +000058 u_register_t scr_el3 = read_scr_el3();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020059
60 write_scr_el3(scr_el3 | SCR_IRQ_BIT);
61 dsb();
62 wfi();
63 write_scr_el3(scr_el3);
64}
65
66static int rcar_pwr_domain_on(u_register_t mpidr)
67{
68 rcar_program_mailbox(mpidr, rcar_sec_entrypoint);
69 rcar_pwrc_cpuon(mpidr);
70
71 return PSCI_E_SUCCESS;
72}
73
74static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state)
75{
76 uint32_t cluster_type = rcar_pwrc_get_cluster();
77 unsigned long mpidr = read_mpidr_el1();
78
79 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
80 if (cluster_type == RCAR_CLUSTER_A53A57)
81 plat_cci_enable();
82
83 rcar_pwrc_disable_interrupt_wakeup(mpidr);
84 rcar_program_mailbox(mpidr, 0);
85
86 gicv2_cpuif_enable();
87 gicv2_pcpu_distif_init();
88}
89
90static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
91{
Marek Vasut4ae342c2019-01-05 13:56:03 +010092#if RCAR_LSI != RCAR_D3
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020093 uint32_t cluster_type = rcar_pwrc_get_cluster();
Marek Vasut4ae342c2019-01-05 13:56:03 +010094#endif
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +020095 unsigned long mpidr = read_mpidr_el1();
96
97 gicv2_cpuif_disable();
98 rcar_pwrc_cpuoff(mpidr);
99
Marek Vasut4ae342c2019-01-05 13:56:03 +0100100#if RCAR_LSI != RCAR_D3
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200101 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 }
Marek Vasut4ae342c2019-01-05 13:56:03 +0100107#endif
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200108}
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
Toshiyuki Ogasaharab67a8ca2019-03-22 16:14:00 +0900150 rcar_pwrc_restore_timer_state();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200151 rcar_pwrc_setup();
Marek Vasute7246492018-12-31 17:12:45 +0100152 rcar_pwrc_code_copy_to_system_ram();
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200153
154#if RCAR_SYSTEM_SUSPEND
155 rcar_pwrc_init_suspend_to_ram();
156#endif
157finish:
158 rcar_pwr_domain_on_finish(target_state);
159}
160
161static void __dead2 rcar_system_off(void)
162{
163#if PMIC_ROHM_BD9571
164#if PMIC_LEVEL_MODE
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200165 if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
166 ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
167#else
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200168 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
169 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
170#endif
171#else
172 uint64_t cpu = read_mpidr_el1() & 0x0000ffff;
173 int32_t rtn_on;
174
Marek Vasut122555f2019-01-05 16:21:14 +0100175 rtn_on = rcar_pwrc_cpu_on_check(cpu);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200176
177 if (cpu == rcar_boot_mpidr)
178 panic();
179
180 if (rtn_on)
181 panic();
182
183 rcar_pwrc_cpuoff(cpu);
184 rcar_pwrc_clusteroff(cpu);
185
186#endif /* PMIC_ROHM_BD9571 */
187 wfi();
188 ERROR("RCAR System Off: operation not handled.\n");
189 panic();
190}
191
192static void __dead2 rcar_system_reset(void)
193{
194#if PMIC_ROHM_BD9571
195#if PMIC_LEVEL_MODE
196#if RCAR_SYSTEM_RESET_KEEPON_DDR
197 uint8_t mode;
198 int32_t error;
199
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200200 error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC);
201 if (error) {
Biju Dasd9675d32020-12-13 20:38:44 +0000202 ERROR("Failed send KEEP10 magic ret=%d\n", error);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200203 goto done;
204 }
205
206 error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode);
207 if (error) {
Biju Dasd9675d32020-12-13 20:38:44 +0000208 ERROR("Failed receive BKUP_Mode_Cnt ret=%d\n", error);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200209 goto done;
210 }
211
212 mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0;
213 error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode);
214 if (error) {
Biju Dasd9675d32020-12-13 20:38:44 +0000215 ERROR("Failed send KEEPON_DDRx ret=%d\n", error);
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200216 goto done;
217 }
218
219 rcar_pwrc_set_suspend_to_ram();
220done:
221#else
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200222 if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF))
223 ERROR("BL3-1:Failed the SYSTEM-RESET.\n");
224#endif
225#else
226#if (RCAR_GEN3_ULCB == 1)
227 rcar_cpld_reset_cpu();
228#endif
229#endif
230#else
231 rcar_pwrc_system_reset();
232#endif
233 wfi();
234
235 ERROR("RCAR System Reset: operation not handled.\n");
236 panic();
237}
238
239static int rcar_validate_power_state(unsigned int power_state,
240 psci_power_state_t *req_state)
241{
242 unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
243 unsigned int pstate = psci_get_pstate_type(power_state);
244 uint32_t i;
245
246 if (pstate == PSTATE_TYPE_STANDBY) {
247 if (pwr_lvl != MPIDR_AFFLVL0)
248 return PSCI_E_INVALID_PARAMS;
249
250 req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
251 } else {
252 for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
253 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
254 }
255
256 if (psci_get_pstate_id(power_state))
257 return PSCI_E_INVALID_PARAMS;
258
259 return PSCI_E_SUCCESS;
260}
261
262#if RCAR_SYSTEM_SUSPEND
263static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state)
264{
265 unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU;
266 int i;
267
268 if (mpidr != rcar_boot_mpidr)
269 goto deny;
270
271 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
272 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
273
274 return;
275deny:
276 /* deny system suspend entry */
277 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN;
278 for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
279 req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
280}
281#endif
282
283static const plat_psci_ops_t rcar_plat_psci_ops = {
284 .cpu_standby = rcar_cpu_standby,
285 .pwr_domain_on = rcar_pwr_domain_on,
286 .pwr_domain_off = rcar_pwr_domain_off,
287 .pwr_domain_suspend = rcar_pwr_domain_suspend,
288 .pwr_domain_on_finish = rcar_pwr_domain_on_finish,
289 .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish,
290 .system_off = rcar_system_off,
291 .system_reset = rcar_system_reset,
292 .validate_power_state = rcar_validate_power_state,
293#if RCAR_SYSTEM_SUSPEND
Biju Dasd9675d32020-12-13 20:38:44 +0000294 .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state,
Jorge Ramirez-Ortizbf084dc2018-09-23 09:36:13 +0200295#endif
296};
297
298int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops)
299{
300 *psci_ops = &rcar_plat_psci_ops;
301 rcar_sec_entrypoint = sec_entrypoint;
302
303#if RCAR_SYSTEM_SUSPEND
304 rcar_pwrc_init_suspend_to_ram();
305#endif
306 return 0;
307}
308