1 /*
2  * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <stdbool.h>
9 
10 #include <arch_helpers.h>
11 #include <common/debug.h>
12 #include <lib/el3_runtime/cpu_data.h>
13 #include <lib/psci/psci.h>
14 #include <plat/common/platform.h>
15 
16 #include <ti_sci_protocol.h>
17 #include <k3_gicv3.h>
18 #include <ti_sci.h>
19 
20 #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
21 #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
22 #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
23 
24 uintptr_t k3_sec_entrypoint;
25 
k3_cpu_standby(plat_local_state_t cpu_state)26 static void k3_cpu_standby(plat_local_state_t cpu_state)
27 {
28 	u_register_t scr;
29 
30 	scr = read_scr_el3();
31 	/* Enable the Non secure interrupt to wake the CPU */
32 	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
33 	isb();
34 	/* dsb is good practice before using wfi to enter low power states */
35 	dsb();
36 	/* Enter standby state */
37 	wfi();
38 	/* Restore SCR */
39 	write_scr_el3(scr);
40 }
41 
k3_pwr_domain_on(u_register_t mpidr)42 static int k3_pwr_domain_on(u_register_t mpidr)
43 {
44 	int core, proc_id, device_id, ret;
45 
46 	core = plat_core_pos_by_mpidr(mpidr);
47 	if (core < 0) {
48 		ERROR("Could not get target core id: %d\n", core);
49 		return PSCI_E_INTERN_FAIL;
50 	}
51 
52 	proc_id = PLAT_PROC_START_ID + core;
53 	device_id = PLAT_PROC_DEVICE_START_ID + core;
54 
55 	ret = ti_sci_proc_request(proc_id);
56 	if (ret) {
57 		ERROR("Request for processor failed: %d\n", ret);
58 		return PSCI_E_INTERN_FAIL;
59 	}
60 
61 	ret = ti_sci_proc_set_boot_cfg(proc_id, k3_sec_entrypoint, 0, 0);
62 	if (ret) {
63 		ERROR("Request to set core boot address failed: %d\n", ret);
64 		return PSCI_E_INTERN_FAIL;
65 	}
66 
67 	/* sanity check these are off before starting a core */
68 	ret = ti_sci_proc_set_boot_ctrl(proc_id,
69 			0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ |
70 			   PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS |
71 			   PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM);
72 	if (ret) {
73 		ERROR("Request to clear boot configuration failed: %d\n", ret);
74 		return PSCI_E_INTERN_FAIL;
75 	}
76 
77 	ret = ti_sci_device_get(device_id);
78 	if (ret) {
79 		ERROR("Request to start core failed: %d\n", ret);
80 		return PSCI_E_INTERN_FAIL;
81 	}
82 
83 	return PSCI_E_SUCCESS;
84 }
85 
k3_pwr_domain_off(const psci_power_state_t * target_state)86 void k3_pwr_domain_off(const psci_power_state_t *target_state)
87 {
88 	int core, cluster, proc_id, device_id, cluster_id, ret;
89 
90 	/* At very least the local core should be powering down */
91 	assert(CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE);
92 
93 	/* Prevent interrupts from spuriously waking up this cpu */
94 	k3_gic_cpuif_disable();
95 
96 	core = plat_my_core_pos();
97 	cluster = MPIDR_AFFLVL1_VAL(read_mpidr_el1());
98 	proc_id = PLAT_PROC_START_ID + core;
99 	device_id = PLAT_PROC_DEVICE_START_ID + core;
100 	cluster_id = PLAT_CLUSTER_DEVICE_START_ID + (cluster * 2);
101 
102 	/*
103 	 * If we are the last core in the cluster then we take a reference to
104 	 * the cluster device so that it does not get shutdown before we
105 	 * execute the entire cluster L2 cleaning sequence below.
106 	 */
107 	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
108 		ret = ti_sci_device_get(cluster_id);
109 		if (ret) {
110 			ERROR("Request to get cluster failed: %d\n", ret);
111 			return;
112 		}
113 	}
114 
115 	/* Start by sending wait for WFI command */
116 	ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
117 			/*
118 			 * Wait maximum time to give us the best chance to get
119 			 * to WFI before this command timeouts
120 			 */
121 			UINT8_MAX, 100, UINT8_MAX, UINT8_MAX,
122 			/* Wait for WFI */
123 			PROC_BOOT_STATUS_FLAG_ARMV8_WFI, 0, 0, 0);
124 	if (ret) {
125 		ERROR("Sending wait for WFI failed (%d)\n", ret);
126 		return;
127 	}
128 
129 	/* Now queue up the core shutdown request */
130 	ret = ti_sci_device_put_no_wait(device_id);
131 	if (ret) {
132 		ERROR("Sending core shutdown message failed (%d)\n", ret);
133 		return;
134 	}
135 
136 	/* If our cluster is not going down we stop here */
137 	if (CLUSTER_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
138 		return;
139 
140 	/* set AINACTS */
141 	ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
142 			PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS, 0);
143 	if (ret) {
144 		ERROR("Sending set control message failed (%d)\n", ret);
145 		return;
146 	}
147 
148 	/* set L2FLUSHREQ */
149 	ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
150 			PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ, 0);
151 	if (ret) {
152 		ERROR("Sending set control message failed (%d)\n", ret);
153 		return;
154 	}
155 
156 	/* wait for L2FLUSHDONE*/
157 	ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
158 			UINT8_MAX, 2, UINT8_MAX, UINT8_MAX,
159 			PROC_BOOT_STATUS_FLAG_ARMV8_L2F_DONE, 0, 0, 0);
160 	if (ret) {
161 		ERROR("Sending wait message failed (%d)\n", ret);
162 		return;
163 	}
164 
165 	/* clear L2FLUSHREQ */
166 	ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
167 			0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ);
168 	if (ret) {
169 		ERROR("Sending set control message failed (%d)\n", ret);
170 		return;
171 	}
172 
173 	/* set ACINACTM */
174 	ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id,
175 			PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM, 0);
176 	if (ret) {
177 		ERROR("Sending set control message failed (%d)\n", ret);
178 		return;
179 	}
180 
181 	/* wait for STANDBYWFIL2 */
182 	ret = ti_sci_proc_wait_boot_status_no_wait(proc_id,
183 			UINT8_MAX, 2, UINT8_MAX, UINT8_MAX,
184 			PROC_BOOT_STATUS_FLAG_ARMV8_STANDBYWFIL2, 0, 0, 0);
185 	if (ret) {
186 		ERROR("Sending wait message failed (%d)\n", ret);
187 		return;
188 	}
189 
190 	/* Now queue up the cluster shutdown request */
191 	ret = ti_sci_device_put_no_wait(cluster_id);
192 	if (ret) {
193 		ERROR("Sending cluster shutdown message failed (%d)\n", ret);
194 		return;
195 	}
196 }
197 
k3_pwr_domain_on_finish(const psci_power_state_t * target_state)198 void k3_pwr_domain_on_finish(const psci_power_state_t *target_state)
199 {
200 	/* TODO: Indicate to System firmware about completion */
201 
202 	k3_gic_pcpu_init();
203 	k3_gic_cpuif_enable();
204 }
205 
k3_system_off(void)206 static void __dead2 k3_system_off(void)
207 {
208 	ERROR("System Off: operation not handled.\n");
209 	while (true)
210 		wfi();
211 }
212 
k3_system_reset(void)213 static void __dead2 k3_system_reset(void)
214 {
215 	/* Send the system reset request to system firmware */
216 	ti_sci_core_reboot();
217 
218 	while (true)
219 		wfi();
220 }
221 
k3_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)222 static int k3_validate_power_state(unsigned int power_state,
223 				   psci_power_state_t *req_state)
224 {
225 	/* TODO: perform the proper validation */
226 
227 	return PSCI_E_SUCCESS;
228 }
229 
k3_validate_ns_entrypoint(uintptr_t entrypoint)230 static int k3_validate_ns_entrypoint(uintptr_t entrypoint)
231 {
232 	/* TODO: perform the proper validation */
233 
234 	return PSCI_E_SUCCESS;
235 }
236 
237 #if K3_PM_SYSTEM_SUSPEND
k3_pwr_domain_suspend(const psci_power_state_t * target_state)238 static void k3_pwr_domain_suspend(const psci_power_state_t *target_state)
239 {
240 	unsigned int core, proc_id;
241 
242 	core = plat_my_core_pos();
243 	proc_id = PLAT_PROC_START_ID + core;
244 
245 	/* Prevent interrupts from spuriously waking up this cpu */
246 	k3_gic_cpuif_disable();
247 	k3_gic_save_context();
248 
249 	k3_pwr_domain_off(target_state);
250 
251 	ti_sci_enter_sleep(proc_id, 0, k3_sec_entrypoint);
252 }
253 
k3_pwr_domain_suspend_finish(const psci_power_state_t * target_state)254 static void k3_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
255 {
256 	k3_gic_restore_context();
257 	k3_gic_cpuif_enable();
258 }
259 
k3_get_sys_suspend_power_state(psci_power_state_t * req_state)260 static void k3_get_sys_suspend_power_state(psci_power_state_t *req_state)
261 {
262 	unsigned int i;
263 
264 	/* CPU & cluster off, system in retention */
265 	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) {
266 		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
267 	}
268 }
269 #endif
270 
271 static const plat_psci_ops_t k3_plat_psci_ops = {
272 	.cpu_standby = k3_cpu_standby,
273 	.pwr_domain_on = k3_pwr_domain_on,
274 	.pwr_domain_off = k3_pwr_domain_off,
275 	.pwr_domain_on_finish = k3_pwr_domain_on_finish,
276 #if K3_PM_SYSTEM_SUSPEND
277 	.pwr_domain_suspend = k3_pwr_domain_suspend,
278 	.pwr_domain_suspend_finish = k3_pwr_domain_suspend_finish,
279 	.get_sys_suspend_power_state = k3_get_sys_suspend_power_state,
280 #endif
281 	.system_off = k3_system_off,
282 	.system_reset = k3_system_reset,
283 	.validate_power_state = k3_validate_power_state,
284 	.validate_ns_entrypoint = k3_validate_ns_entrypoint
285 };
286 
plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)287 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
288 			const plat_psci_ops_t **psci_ops)
289 {
290 	k3_sec_entrypoint = sec_entrypoint;
291 
292 	*psci_ops = &k3_plat_psci_ops;
293 
294 	return 0;
295 }
296