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