• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <arch_helpers.h>
8 #include <assert.h>
9 #include <css_def.h>
10 #include <css_pm.h>
11 #include <debug.h>
12 #include <plat_arm.h>
13 #include <platform.h>
14 #include <string.h>
15 #include "../scmi/scmi.h"
16 #include "css_scp.h"
17 
18 /*
19  * This file implements the SCP helper functions using SCMI protocol.
20  */
21 
22 /*
23  * SCMI power state parameter bit field encoding for ARM CSS platforms.
24  *
25  * 31  20 19       16 15      12 11       8 7        4 3         0
26  * +-------------------------------------------------------------+
27  * | SBZ | Max level |  Level 3 |  Level 2 |  Level 1 |  Level 0 |
28  * |     |           |   state  |   state  |   state  |   state  |
29  * +-------------------------------------------------------------+
30  *
31  * `Max level` encodes the highest level that has a valid power state
32  * encoded in the power state.
33  */
34 #define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT	16
35 #define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH	4
36 #define SCMI_PWR_STATE_MAX_PWR_LVL_MASK		\
37 				((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1)
38 #define SCMI_SET_PWR_STATE_MAX_PWR_LVL(pwr_state, max_lvl)		\
39 		(pwr_state) |= ((max_lvl) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)	\
40 				<< SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT
41 #define SCMI_GET_PWR_STATE_MAX_PWR_LVL(pwr_state)		\
42 		(((pwr_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT)	\
43 				& SCMI_PWR_STATE_MAX_PWR_LVL_MASK)
44 
45 #define SCMI_PWR_STATE_LVL_WIDTH		4
46 #define SCMI_PWR_STATE_LVL_MASK			\
47 				((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1)
48 #define SCMI_SET_PWR_STATE_LVL(pwr_state, lvl, lvl_state)		\
49 		(pwr_state) |= ((lvl_state) & SCMI_PWR_STATE_LVL_MASK)	\
50 				<< (SCMI_PWR_STATE_LVL_WIDTH * (lvl))
51 #define SCMI_GET_PWR_STATE_LVL(pwr_state, lvl)		\
52 		(((pwr_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (lvl))) &	\
53 				SCMI_PWR_STATE_LVL_MASK)
54 
55 /*
56  * The SCMI power state enumeration for a power domain level
57  */
58 typedef enum {
59 	scmi_power_state_off = 0,
60 	scmi_power_state_on = 1,
61 	scmi_power_state_sleep = 2,
62 } scmi_power_state_t;
63 
64 /*
65  * This mapping array has to be exported by the platform. Each element at
66  * a given index maps that core to an SCMI power domain.
67  */
68 extern uint32_t plat_css_core_pos_to_scmi_dmn_id_map[];
69 
70 /*
71  * The global handle for invoking the SCMI driver APIs after the driver
72  * has been initialized.
73  */
74 void *scmi_handle;
75 
76 /* The SCMI channel global object */
77 static scmi_channel_t scmi_channel;
78 
79 ARM_INSTANTIATE_LOCK;
80 
81 /*
82  * Helper function to suspend a CPU power domain and its parent power domains
83  * if applicable.
84  */
css_scp_suspend(const psci_power_state_t * target_state)85 void css_scp_suspend(const psci_power_state_t *target_state)
86 {
87 	int lvl, ret;
88 	uint32_t scmi_pwr_state = 0;
89 
90 	/* At least power domain level 0 should be specified to be suspended */
91 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
92 						ARM_LOCAL_STATE_OFF);
93 
94 	/* Check if power down at system power domain level is requested */
95 	if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
96 		/* Issue SCMI command for SYSTEM_SUSPEND */
97 		ret = scmi_sys_pwr_state_set(scmi_handle,
98 				SCMI_SYS_PWR_FORCEFUL_REQ,
99 				SCMI_SYS_PWR_SUSPEND);
100 		if (ret != SCMI_E_SUCCESS) {
101 			ERROR("SCMI system power domain suspend return 0x%x unexpected\n",
102 					ret);
103 			panic();
104 		}
105 		return;
106 	}
107 
108 	/*
109 	 * If we reach here, then assert that power down at system power domain
110 	 * level is running.
111 	 */
112 	assert(target_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] ==
113 							ARM_LOCAL_STATE_RUN);
114 
115 	/* For level 0, specify `scmi_power_state_sleep` as the power state */
116 	SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, ARM_PWR_LVL0,
117 						scmi_power_state_sleep);
118 
119 	for (lvl = ARM_PWR_LVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
120 		if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN)
121 			break;
122 
123 		assert(target_state->pwr_domain_state[lvl] ==
124 							ARM_LOCAL_STATE_OFF);
125 		/*
126 		 * Specify `scmi_power_state_off` as power state for higher
127 		 * levels.
128 		 */
129 		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
130 						scmi_power_state_off);
131 	}
132 
133 	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
134 
135 	ret = scmi_pwr_state_set(scmi_handle,
136 		plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
137 		scmi_pwr_state);
138 
139 	if (ret != SCMI_E_SUCCESS) {
140 		ERROR("SCMI set power state command return 0x%x unexpected\n",
141 				ret);
142 		panic();
143 	}
144 }
145 
146 /*
147  * Helper function to turn off a CPU power domain and its parent power domains
148  * if applicable.
149  */
css_scp_off(const psci_power_state_t * target_state)150 void css_scp_off(const psci_power_state_t *target_state)
151 {
152 	int lvl = 0, ret;
153 	uint32_t scmi_pwr_state = 0;
154 
155 	/* At-least the CPU level should be specified to be OFF */
156 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
157 							ARM_LOCAL_STATE_OFF);
158 
159 	/* PSCI CPU OFF cannot be used to turn OFF system power domain */
160 	assert(target_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] ==
161 							ARM_LOCAL_STATE_RUN);
162 
163 	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
164 		if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN)
165 			break;
166 
167 		assert(target_state->pwr_domain_state[lvl] ==
168 							ARM_LOCAL_STATE_OFF);
169 		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
170 				scmi_power_state_off);
171 	}
172 
173 	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
174 
175 	ret = scmi_pwr_state_set(scmi_handle,
176 		plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
177 		scmi_pwr_state);
178 
179 	if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
180 		ERROR("SCMI set power state command return 0x%x unexpected\n",
181 				ret);
182 		panic();
183 	}
184 }
185 
186 /*
187  * Helper function to turn ON a CPU power domain and its parent power domains
188  * if applicable.
189  */
css_scp_on(u_register_t mpidr)190 void css_scp_on(u_register_t mpidr)
191 {
192 	int lvl = 0, ret, core_pos;
193 	uint32_t scmi_pwr_state = 0;
194 
195 	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++)
196 		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
197 				scmi_power_state_on);
198 
199 	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
200 
201 	core_pos = plat_core_pos_by_mpidr(mpidr);
202 	assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT);
203 
204 	ret = scmi_pwr_state_set(scmi_handle,
205 		plat_css_core_pos_to_scmi_dmn_id_map[core_pos],
206 		scmi_pwr_state);
207 
208 	if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
209 		ERROR("SCMI set power state command return 0x%x unexpected\n",
210 				ret);
211 		panic();
212 	}
213 }
214 
215 /*
216  * Helper function to get the power state of a power domain node as reported
217  * by the SCP.
218  */
css_scp_get_power_state(u_register_t mpidr,unsigned int power_level)219 int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
220 {
221 	int ret, cpu_idx;
222 	uint32_t scmi_pwr_state = 0, lvl_state;
223 
224 	/* We don't support get power state at the system power domain level */
225 	if ((power_level > PLAT_MAX_PWR_LVL) ||
226 			(power_level == CSS_SYSTEM_PWR_DMN_LVL)) {
227 		WARN("Invalid power level %u specified for SCMI get power state\n",
228 				power_level);
229 		return PSCI_E_INVALID_PARAMS;
230 	}
231 
232 	cpu_idx = plat_core_pos_by_mpidr(mpidr);
233 	assert(cpu_idx > -1);
234 
235 	ret = scmi_pwr_state_get(scmi_handle,
236 		plat_css_core_pos_to_scmi_dmn_id_map[cpu_idx],
237 		&scmi_pwr_state);
238 
239 	if (ret != SCMI_E_SUCCESS) {
240 		WARN("SCMI get power state command return 0x%x unexpected\n",
241 				ret);
242 		return PSCI_E_INVALID_PARAMS;
243 	}
244 
245 	/*
246 	 * Find the maximum power level described in the get power state
247 	 * command. If it is less than the requested power level, then assume
248 	 * the requested power level is ON.
249 	 */
250 	if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state) < power_level)
251 		return HW_ON;
252 
253 	lvl_state = SCMI_GET_PWR_STATE_LVL(scmi_pwr_state, power_level);
254 	if (lvl_state == scmi_power_state_on)
255 		return HW_ON;
256 
257 	assert((lvl_state == scmi_power_state_off) ||
258 				(lvl_state == scmi_power_state_sleep));
259 	return HW_OFF;
260 }
261 
css_scp_system_off(int state)262 void __dead2 css_scp_system_off(int state)
263 {
264 	int ret;
265 
266 	/*
267 	 * Disable GIC CPU interface to prevent pending interrupt from waking
268 	 * up the AP from WFI.
269 	 */
270 	plat_arm_gic_cpuif_disable();
271 
272 	/*
273 	 * Issue SCMI command. First issue a graceful
274 	 * request and if that fails force the request.
275 	 */
276 	ret = scmi_sys_pwr_state_set(scmi_handle,
277 			SCMI_SYS_PWR_FORCEFUL_REQ,
278 			state);
279 
280 	if (ret != SCMI_E_SUCCESS) {
281 		ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n",
282 			state, ret);
283 		panic();
284 	}
285 	wfi();
286 	ERROR("CSS set power state: operation not handled.\n");
287 	panic();
288 }
289 
290 /*
291  * Helper function to shutdown the system via SCMI.
292  */
css_scp_sys_shutdown(void)293 void __dead2 css_scp_sys_shutdown(void)
294 {
295 	css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN);
296 }
297 
298 /*
299  * Helper function to reset the system via SCMI.
300  */
css_scp_sys_reboot(void)301 void __dead2 css_scp_sys_reboot(void)
302 {
303 	css_scp_system_off(SCMI_SYS_PWR_COLD_RESET);
304 }
305 
306 scmi_channel_plat_info_t plat_css_scmi_plat_info = {
307 		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
308 		.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
309 		.db_preserve_mask = 0xfffffffe,
310 		.db_modify_mask = 0x1,
311 };
312 
plat_arm_pwrc_setup(void)313 void plat_arm_pwrc_setup(void)
314 {
315 	scmi_channel.info = &plat_css_scmi_plat_info;
316 	scmi_channel.lock = ARM_LOCK_GET_INSTANCE;
317 	scmi_handle = scmi_init(&scmi_channel);
318 	if (scmi_handle == NULL) {
319 		ERROR("SCMI Initialization failed\n");
320 		panic();
321 	}
322 }
323 
324 /******************************************************************************
325  * This function overrides the default definition for ARM platforms. Initialize
326  * the SCMI driver, query capability via SCMI and modify the PSCI capability
327  * based on that.
328  *****************************************************************************/
plat_arm_psci_override_pm_ops(plat_psci_ops_t * ops)329 const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
330 {
331 	uint32_t msg_attr;
332 	int ret;
333 
334 	assert(scmi_handle);
335 
336 	/* Check that power domain POWER_STATE_SET message is supported */
337 	ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID,
338 				SCMI_PWR_STATE_SET_MSG, &msg_attr);
339 	if (ret != SCMI_E_SUCCESS) {
340 		ERROR("Set power state command is not supported by SCMI\n");
341 		panic();
342 	}
343 
344 	/*
345 	 * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support
346 	 * POWER_STATE_GET message.
347 	 */
348 	ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID,
349 				SCMI_PWR_STATE_GET_MSG, &msg_attr);
350 	if (ret != SCMI_E_SUCCESS)
351 		ops->get_node_hw_state = NULL;
352 
353 	/* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */
354 	ret = scmi_proto_msg_attr(scmi_handle, SCMI_SYS_PWR_PROTO_ID,
355 				SCMI_SYS_PWR_STATE_SET_MSG, &msg_attr);
356 	if (ret != SCMI_E_SUCCESS) {
357 		/* System power management operations are not supported */
358 		ops->system_off = NULL;
359 		ops->system_reset = NULL;
360 		ops->get_sys_suspend_power_state = NULL;
361 	} else {
362 		if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) {
363 			/*
364 			 * System power management protocol is available, but
365 			 * it does not support SYSTEM SUSPEND.
366 			 */
367 			ops->get_sys_suspend_power_state = NULL;
368 		}
369 		if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) {
370 			/*
371 			 * WARM reset is not available.
372 			 */
373 			ops->system_reset2 = NULL;
374 		}
375 	}
376 
377 	return ops;
378 }
379 
css_system_reset2(int is_vendor,int reset_type,u_register_t cookie)380 int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
381 {
382 	if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET))
383 		return PSCI_E_INVALID_PARAMS;
384 
385 	css_scp_system_off(SCMI_SYS_PWR_WARM_RESET);
386 	/*
387 	 * css_scp_system_off cannot return (it is a __dead function),
388 	 * but css_system_reset2 has to return some value, even in
389 	 * this case.
390 	 */
391 	return 0;
392 }
393