2 * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
10 #include <arch_helpers.h>
11 #include <common/debug.h>
12 #include <drivers/arm/css/css_scp.h>
13 #include <drivers/arm/css/scmi.h>
14 #include <plat/arm/common/plat_arm.h>
15 #include <plat/arm/css/common/css_pm.h>
16 #include <plat/common/platform.h>
17 #include <platform_def.h>
20 * This file implements the SCP helper functions using SCMI protocol.
24 * SCMI power state parameter bit field encoding for ARM CSS platforms.
26 * 31 20 19 16 15 12 11 8 7 4 3 0
27 * +-------------------------------------------------------------+
28 * | SBZ | Max level | Level 3 | Level 2 | Level 1 | Level 0 |
29 * | | | state | state | state | state |
30 * +-------------------------------------------------------------+
32 * `Max level` encodes the highest level that has a valid power state
33 * encoded in the power state.
35 #define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 16
36 #define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH 4
37 #define SCMI_PWR_STATE_MAX_PWR_LVL_MASK \
38 ((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1)
39 #define SCMI_SET_PWR_STATE_MAX_PWR_LVL(_power_state, _max_level) \
40 (_power_state) |= ((_max_level) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)\
41 << SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT
42 #define SCMI_GET_PWR_STATE_MAX_PWR_LVL(_power_state) \
43 (((_power_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT) \
44 & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)
46 #define SCMI_PWR_STATE_LVL_WIDTH 4
47 #define SCMI_PWR_STATE_LVL_MASK \
48 ((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1)
49 #define SCMI_SET_PWR_STATE_LVL(_power_state, _level, _level_state) \
50 (_power_state) |= ((_level_state) & SCMI_PWR_STATE_LVL_MASK) \
51 << (SCMI_PWR_STATE_LVL_WIDTH * (_level))
52 #define SCMI_GET_PWR_STATE_LVL(_power_state, _level) \
53 (((_power_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (_level))) & \
54 SCMI_PWR_STATE_LVL_MASK)
57 * The SCMI power state enumeration for a power domain level
60 scmi_power_state_off
= 0,
61 scmi_power_state_on
= 1,
62 scmi_power_state_sleep
= 2,
66 * The global handle for invoking the SCMI driver APIs after the driver
67 * has been initialized.
69 static void *scmi_handle
;
71 /* The SCMI channel global object */
72 static scmi_channel_t channel
;
74 ARM_SCMI_INSTANTIATE_LOCK
;
77 * Helper function to suspend a CPU power domain and its parent power domains
80 void css_scp_suspend(const struct psci_power_state
*target_state
)
84 /* At least power domain level 0 should be specified to be suspended */
85 assert(target_state
->pwr_domain_state
[ARM_PWR_LVL0
] ==
88 /* Check if power down at system power domain level is requested */
89 if (css_system_pwr_state(target_state
) == ARM_LOCAL_STATE_OFF
) {
90 /* Issue SCMI command for SYSTEM_SUSPEND */
91 ret
= scmi_sys_pwr_state_set(scmi_handle
,
92 SCMI_SYS_PWR_FORCEFUL_REQ
,
93 SCMI_SYS_PWR_SUSPEND
);
94 if (ret
!= SCMI_E_SUCCESS
) {
95 ERROR("SCMI system power domain suspend return 0x%x unexpected\n",
101 #if !HW_ASSISTED_COHERENCY
103 uint32_t scmi_pwr_state
= 0;
105 * If we reach here, then assert that power down at system power domain
108 assert(css_system_pwr_state(target_state
) == ARM_LOCAL_STATE_RUN
);
110 /* For level 0, specify `scmi_power_state_sleep` as the power state */
111 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state
, ARM_PWR_LVL0
,
112 scmi_power_state_sleep
);
114 for (lvl
= ARM_PWR_LVL1
; lvl
<= PLAT_MAX_PWR_LVL
; lvl
++) {
115 if (target_state
->pwr_domain_state
[lvl
] == ARM_LOCAL_STATE_RUN
)
118 assert(target_state
->pwr_domain_state
[lvl
] ==
119 ARM_LOCAL_STATE_OFF
);
121 * Specify `scmi_power_state_off` as power state for higher
124 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state
, lvl
,
125 scmi_power_state_off
);
128 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state
, lvl
- 1);
130 ret
= scmi_pwr_state_set(scmi_handle
,
131 plat_css_core_pos_to_scmi_dmn_id_map
[plat_my_core_pos()],
134 if (ret
!= SCMI_E_SUCCESS
) {
135 ERROR("SCMI set power state command return 0x%x unexpected\n",
143 * Helper function to turn off a CPU power domain and its parent power domains
146 void css_scp_off(const struct psci_power_state
*target_state
)
148 unsigned int lvl
= 0;
150 uint32_t scmi_pwr_state
= 0;
152 /* At-least the CPU level should be specified to be OFF */
153 assert(target_state
->pwr_domain_state
[ARM_PWR_LVL0
] ==
154 ARM_LOCAL_STATE_OFF
);
156 /* PSCI CPU OFF cannot be used to turn OFF system power domain */
157 assert(css_system_pwr_state(target_state
) == ARM_LOCAL_STATE_RUN
);
159 for (; lvl
<= PLAT_MAX_PWR_LVL
; lvl
++) {
160 if (target_state
->pwr_domain_state
[lvl
] == ARM_LOCAL_STATE_RUN
)
163 assert(target_state
->pwr_domain_state
[lvl
] ==
164 ARM_LOCAL_STATE_OFF
);
165 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state
, lvl
,
166 scmi_power_state_off
);
169 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state
, lvl
- 1);
171 ret
= scmi_pwr_state_set(scmi_handle
,
172 plat_css_core_pos_to_scmi_dmn_id_map
[plat_my_core_pos()],
175 if (ret
!= SCMI_E_QUEUED
&& ret
!= SCMI_E_SUCCESS
) {
176 ERROR("SCMI set power state command return 0x%x unexpected\n",
183 * Helper function to turn ON a CPU power domain and its parent power domains
186 void css_scp_on(u_register_t mpidr
)
188 unsigned int lvl
= 0;
190 uint32_t scmi_pwr_state
= 0;
192 for (; lvl
<= PLAT_MAX_PWR_LVL
; lvl
++)
193 SCMI_SET_PWR_STATE_LVL(scmi_pwr_state
, lvl
,
194 scmi_power_state_on
);
196 SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state
, lvl
- 1);
198 core_pos
= plat_core_pos_by_mpidr(mpidr
);
199 assert(core_pos
>= 0 && core_pos
< PLATFORM_CORE_COUNT
);
201 ret
= scmi_pwr_state_set(scmi_handle
,
202 plat_css_core_pos_to_scmi_dmn_id_map
[core_pos
],
205 if (ret
!= SCMI_E_QUEUED
&& ret
!= SCMI_E_SUCCESS
) {
206 ERROR("SCMI set power state command return 0x%x unexpected\n",
213 * Helper function to get the power state of a power domain node as reported
216 int css_scp_get_power_state(u_register_t mpidr
, unsigned int power_level
)
219 uint32_t scmi_pwr_state
= 0, lvl_state
;
221 /* We don't support get power state at the system power domain level */
222 if ((power_level
> PLAT_MAX_PWR_LVL
) ||
223 (power_level
== CSS_SYSTEM_PWR_DMN_LVL
)) {
224 WARN("Invalid power level %u specified for SCMI get power state\n",
226 return PSCI_E_INVALID_PARAMS
;
229 cpu_idx
= plat_core_pos_by_mpidr(mpidr
);
230 assert(cpu_idx
> -1);
232 ret
= scmi_pwr_state_get(scmi_handle
,
233 plat_css_core_pos_to_scmi_dmn_id_map
[cpu_idx
],
236 if (ret
!= SCMI_E_SUCCESS
) {
237 WARN("SCMI get power state command return 0x%x unexpected\n",
239 return PSCI_E_INVALID_PARAMS
;
243 * Find the maximum power level described in the get power state
244 * command. If it is less than the requested power level, then assume
245 * the requested power level is ON.
247 if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state
) < power_level
)
250 lvl_state
= SCMI_GET_PWR_STATE_LVL(scmi_pwr_state
, power_level
);
251 if (lvl_state
== scmi_power_state_on
)
254 assert((lvl_state
== scmi_power_state_off
) ||
255 (lvl_state
== scmi_power_state_sleep
));
259 void __dead2
css_scp_system_off(int state
)
264 * Disable GIC CPU interface to prevent pending interrupt from waking
265 * up the AP from WFI.
267 plat_arm_gic_cpuif_disable();
270 * Issue SCMI command. First issue a graceful
271 * request and if that fails force the request.
273 ret
= scmi_sys_pwr_state_set(scmi_handle
,
274 SCMI_SYS_PWR_FORCEFUL_REQ
,
277 if (ret
!= SCMI_E_SUCCESS
) {
278 ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n",
283 ERROR("CSS set power state: operation not handled.\n");
288 * Helper function to shutdown the system via SCMI.
290 void __dead2
css_scp_sys_shutdown(void)
292 css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN
);
296 * Helper function to reset the system via SCMI.
298 void __dead2
css_scp_sys_reboot(void)
300 css_scp_system_off(SCMI_SYS_PWR_COLD_RESET
);
303 static int scmi_ap_core_init(scmi_channel_t
*ch
)
305 #if PROGRAMMABLE_RESET_ADDRESS
309 ret
= scmi_proto_version(ch
, SCMI_AP_CORE_PROTO_ID
, &version
);
310 if (ret
!= SCMI_E_SUCCESS
) {
311 WARN("SCMI AP core protocol version message failed\n");
315 if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER
, version
)) {
316 WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n",
317 version
, SCMI_AP_CORE_PROTO_VER
);
320 INFO("SCMI AP core protocol version 0x%x detected\n", version
);
325 void __init
plat_arm_pwrc_setup(void)
327 channel
.info
= plat_css_get_scmi_info();
328 channel
.lock
= ARM_SCMI_LOCK_GET_INSTANCE
;
329 scmi_handle
= scmi_init(&channel
);
330 if (scmi_handle
== NULL
) {
331 ERROR("SCMI Initialization failed\n");
334 if (scmi_ap_core_init(&channel
) < 0) {
335 ERROR("SCMI AP core protocol initialization failed\n");
340 /******************************************************************************
341 * This function overrides the default definition for ARM platforms. Initialize
342 * the SCMI driver, query capability via SCMI and modify the PSCI capability
344 *****************************************************************************/
345 const plat_psci_ops_t
*css_scmi_override_pm_ops(plat_psci_ops_t
*ops
)
352 /* Check that power domain POWER_STATE_SET message is supported */
353 ret
= scmi_proto_msg_attr(scmi_handle
, SCMI_PWR_DMN_PROTO_ID
,
354 SCMI_PWR_STATE_SET_MSG
, &msg_attr
);
355 if (ret
!= SCMI_E_SUCCESS
) {
356 ERROR("Set power state command is not supported by SCMI\n");
361 * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support
362 * POWER_STATE_GET message.
364 ret
= scmi_proto_msg_attr(scmi_handle
, SCMI_PWR_DMN_PROTO_ID
,
365 SCMI_PWR_STATE_GET_MSG
, &msg_attr
);
366 if (ret
!= SCMI_E_SUCCESS
)
367 ops
->get_node_hw_state
= NULL
;
369 /* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */
370 ret
= scmi_proto_msg_attr(scmi_handle
, SCMI_SYS_PWR_PROTO_ID
,
371 SCMI_SYS_PWR_STATE_SET_MSG
, &msg_attr
);
372 if (ret
!= SCMI_E_SUCCESS
) {
373 /* System power management operations are not supported */
374 ops
->system_off
= NULL
;
375 ops
->system_reset
= NULL
;
376 ops
->get_sys_suspend_power_state
= NULL
;
378 if (!(msg_attr
& SCMI_SYS_PWR_SUSPEND_SUPPORTED
)) {
380 * System power management protocol is available, but
381 * it does not support SYSTEM SUSPEND.
383 ops
->get_sys_suspend_power_state
= NULL
;
385 if (!(msg_attr
& SCMI_SYS_PWR_WARM_RESET_SUPPORTED
)) {
387 * WARM reset is not available.
389 ops
->system_reset2
= NULL
;
396 int css_system_reset2(int is_vendor
, int reset_type
, u_register_t cookie
)
398 if (is_vendor
|| (reset_type
!= PSCI_RESET2_SYSTEM_WARM_RESET
))
399 return PSCI_E_INVALID_PARAMS
;
401 css_scp_system_off(SCMI_SYS_PWR_WARM_RESET
);
403 * css_scp_system_off cannot return (it is a __dead function),
404 * but css_system_reset2 has to return some value, even in
410 #if PROGRAMMABLE_RESET_ADDRESS
411 void plat_arm_program_trusted_mailbox(uintptr_t address
)
416 ret
= scmi_ap_core_set_reset_addr(scmi_handle
, address
,
417 SCMI_AP_CORE_LOCK_ATTR
);
418 if (ret
!= SCMI_E_SUCCESS
) {
419 ERROR("CSS: Failed to program reset address: %d\n", ret
);