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