• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <errno.h>
8 
9 #include <platform_def.h>
10 
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>
20 
21 #include "iic_dvfs.h"
22 #include "pwrc.h"
23 #include "rcar_def.h"
24 #include "rcar_private.h"
25 #include "ulcb_cpld.h"
26 
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 
38 extern void rcar_pwrc_restore_generic_timer(uint64_t *stack);
39 extern void plat_rcar_gic_driver_init(void);
40 extern void plat_rcar_gic_init(void);
41 extern u_register_t rcar_boot_mpidr;
42 
43 static uintptr_t rcar_sec_entrypoint;
44 
rcar_program_mailbox(uint64_t mpidr,uint64_t address)45 static 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 
rcar_cpu_standby(plat_local_state_t cpu_state)57 static void rcar_cpu_standby(plat_local_state_t cpu_state)
58 {
59 	u_register_t scr_el3 = read_scr_el3();
60 
61 	write_scr_el3(scr_el3 | SCR_IRQ_BIT);
62 	dsb();
63 	wfi();
64 	write_scr_el3(scr_el3);
65 }
66 
rcar_pwr_domain_on(u_register_t mpidr)67 static 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 
rcar_pwr_domain_on_finish(const psci_power_state_t * target_state)75 static 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 
rcar_pwr_domain_off(const psci_power_state_t * target_state)91 static void rcar_pwr_domain_off(const psci_power_state_t *target_state)
92 {
93 #if RCAR_LSI != RCAR_D3
94 	uint32_t cluster_type = rcar_pwrc_get_cluster();
95 #endif
96 	unsigned long mpidr = read_mpidr_el1();
97 
98 	gicv2_cpuif_disable();
99 	rcar_pwrc_cpuoff(mpidr);
100 
101 #if RCAR_LSI != RCAR_D3
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 #endif
109 }
110 
rcar_pwr_domain_suspend(const psci_power_state_t * target_state)111 static 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 
rcar_pwr_domain_suspend_finish(const psci_power_state_t * target_state)137 static 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 
151 	rcar_pwrc_restore_timer_state();
152 	rcar_pwrc_setup();
153 	rcar_pwrc_code_copy_to_system_ram();
154 
155 #if RCAR_SYSTEM_SUSPEND
156 	rcar_pwrc_init_suspend_to_ram();
157 #endif
158 finish:
159 	rcar_pwr_domain_on_finish(target_state);
160 }
161 
rcar_system_off(void)162 static void __dead2 rcar_system_off(void)
163 {
164 #if PMIC_ROHM_BD9571
165 #if PMIC_LEVEL_MODE
166 	if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V))
167 		ERROR("BL3-1:Failed the SYSTEM-OFF.\n");
168 #else
169 	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 
176 	rtn_on = rcar_pwrc_cpu_on_check(cpu);
177 
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 
rcar_system_reset(void)193 static 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 
201 	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();
221 done:
222 #else
223 	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 
rcar_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)240 static 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
rcar_get_sys_suspend_power_state(psci_power_state_t * req_state)264 static 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;
276 deny:
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 
284 static 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 
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)299 int 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 
310