blob: 7e228169ac8462135309035ae6f94aff7a36ef47 [file] [log] [blame]
Soby Mathew200fffd2016-10-21 11:34:59 +01001/*
Roberto Vargas5f5a5e62018-02-12 12:36:17 +00002 * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
Soby Mathew200fffd2016-10-21 11:34:59 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Soby Mathew200fffd2016-10-21 11:34:59 +01005 */
6
Soby Mathew200fffd2016-10-21 11:34:59 +01007#include <assert.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
9#include <arch_helpers.h>
10#include <common/debug.h>
Antonio Nino Diazae9654d2019-01-25 14:23:49 +000011#include <drivers/arm/css/css_scpi.h>
Antonio Nino Diazbd7b7402019-01-25 14:30:04 +000012#include <plat/arm/common/plat_arm.h>
13#include <plat/arm/css/common/css_pm.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000014
Soby Mathew200fffd2016-10-21 11:34:59 +010015#include "css_scp.h"
16
17/*
18 * This file implements the SCP power management functions using SCPI protocol.
19 */
20
21/*
22 * Helper function to inform power down state to SCP.
23 */
Roberto Vargas5f5a5e62018-02-12 12:36:17 +000024void css_scp_suspend(const struct psci_power_state *target_state)
Soby Mathew200fffd2016-10-21 11:34:59 +010025{
26 uint32_t cluster_state = scpi_power_on;
27 uint32_t system_state = scpi_power_on;
28
29 /* Check if power down at system power domain level is requested */
Nariman Poushincd956262018-05-01 09:28:40 +010030 if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF)
Soby Mathew200fffd2016-10-21 11:34:59 +010031 system_state = scpi_power_retention;
32
33 /* Cluster is to be turned off, so disable coherency */
34 if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
35 cluster_state = scpi_power_off;
36
37 /*
38 * Ask the SCP to power down the appropriate components depending upon
39 * their state.
40 */
41 scpi_set_css_power_state(read_mpidr_el1(),
42 scpi_power_off,
43 cluster_state,
44 system_state);
45}
46
47/*
48 * Helper function to turn off a CPU power domain and its parent power domains
49 * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we
50 * call the suspend helper here.
51 */
Roberto Vargas85664f52018-02-12 12:36:17 +000052void css_scp_off(const struct psci_power_state *target_state)
Soby Mathew200fffd2016-10-21 11:34:59 +010053{
54 css_scp_suspend(target_state);
55}
56
57/*
58 * Helper function to turn ON a CPU power domain and its parent power domains
59 * if applicable.
60 */
61void css_scp_on(u_register_t mpidr)
62{
63 /*
64 * SCP takes care of powering up parent power domains so we
65 * only need to care about level 0
66 */
67 scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
68 scpi_power_on);
69}
70
71/*
72 * Helper function to get the power state of a power domain node as reported
73 * by the SCP.
74 */
75int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
76{
77 int rc, element;
78 unsigned int cpu_state, cluster_state;
79
80 /*
81 * The format of 'power_level' is implementation-defined, but 0 must
82 * mean a CPU. We also allow 1 to denote the cluster
83 */
84 if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
85 return PSCI_E_INVALID_PARAMS;
86
87 /* Query SCP */
88 rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state);
89 if (rc != 0)
90 return PSCI_E_INVALID_PARAMS;
91
92 /* Map power states of CPU and cluster to expected PSCI return codes */
93 if (power_level == ARM_PWR_LVL0) {
94 /*
95 * The CPU state returned by SCP is an 8-bit bit mask
96 * corresponding to each CPU in the cluster
97 */
jagadeesh ujja64fa64b2017-05-11 16:32:18 +053098#if ARM_PLAT_MT
99 /*
100 * The current SCPI driver only caters for single-threaded
101 * platforms. Hence we ignore the thread ID (which is always 0)
102 * for such platforms.
103 */
104 element = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
105#else
Soby Mathew200fffd2016-10-21 11:34:59 +0100106 element = mpidr & MPIDR_AFFLVL_MASK;
jagadeesh ujja64fa64b2017-05-11 16:32:18 +0530107#endif /* ARM_PLAT_MT */
Soby Mathew200fffd2016-10-21 11:34:59 +0100108 return CSS_CPU_PWR_STATE(cpu_state, element) ==
109 CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF;
110 } else {
111 assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON ||
112 cluster_state == CSS_CLUSTER_PWR_STATE_OFF);
113 return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON :
114 HW_OFF;
115 }
116}
117
118/*
119 * Helper function to shutdown the system via SCPI.
120 */
121void __dead2 css_scp_sys_shutdown(void)
122{
123 uint32_t response;
124
dp-arm199fb4a2017-04-11 11:48:49 +0100125 /*
126 * Disable GIC CPU interface to prevent pending interrupt
127 * from waking up the AP from WFI.
128 */
129 plat_arm_gic_cpuif_disable();
130
Soby Mathew200fffd2016-10-21 11:34:59 +0100131 /* Send the power down request to the SCP */
132 response = scpi_sys_power_state(scpi_system_shutdown);
133
134 if (response != SCP_OK) {
135 ERROR("CSS System Off: SCP error %u.\n", response);
136 panic();
137 }
138 wfi();
139 ERROR("CSS System Off: operation not handled.\n");
140 panic();
141}
142
143/*
144 * Helper function to reset the system via SCPI.
145 */
146void __dead2 css_scp_sys_reboot(void)
147{
148 uint32_t response;
149
dp-arm199fb4a2017-04-11 11:48:49 +0100150 /*
151 * Disable GIC CPU interface to prevent pending interrupt
152 * from waking up the AP from WFI.
153 */
154 plat_arm_gic_cpuif_disable();
155
Soby Mathew200fffd2016-10-21 11:34:59 +0100156 /* Send the system reset request to the SCP */
157 response = scpi_sys_power_state(scpi_system_reboot);
158
159 if (response != SCP_OK) {
160 ERROR("CSS System Reset: SCP error %u.\n", response);
161 panic();
162 }
163 wfi();
164 ERROR("CSS System Reset: operation not handled.\n");
165 panic();
166}