blob: e22504d1d4a0842f05785f1e01b2ff0473c81ef0 [file] [log] [blame]
Soby Mathew200fffd2016-10-21 11:34:59 +01001/*
2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <arch_helpers.h>
32#include <assert.h>
33#include <css_pm.h>
34#include <debug.h>
35#include "../scpi/css_scpi.h"
36#include "css_scp.h"
37
38/*
39 * This file implements the SCP power management functions using SCPI protocol.
40 */
41
42/*
43 * Helper function to inform power down state to SCP.
44 */
45void css_scp_suspend(const psci_power_state_t *target_state)
46{
47 uint32_t cluster_state = scpi_power_on;
48 uint32_t system_state = scpi_power_on;
49
50 /* Check if power down at system power domain level is requested */
51 if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
52 system_state = scpi_power_retention;
53
54 /* Cluster is to be turned off, so disable coherency */
55 if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
56 cluster_state = scpi_power_off;
57
58 /*
59 * Ask the SCP to power down the appropriate components depending upon
60 * their state.
61 */
62 scpi_set_css_power_state(read_mpidr_el1(),
63 scpi_power_off,
64 cluster_state,
65 system_state);
66}
67
68/*
69 * Helper function to turn off a CPU power domain and its parent power domains
70 * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we
71 * call the suspend helper here.
72 */
73void css_scp_off(const psci_power_state_t *target_state)
74{
75 css_scp_suspend(target_state);
76}
77
78/*
79 * Helper function to turn ON a CPU power domain and its parent power domains
80 * if applicable.
81 */
82void css_scp_on(u_register_t mpidr)
83{
84 /*
85 * SCP takes care of powering up parent power domains so we
86 * only need to care about level 0
87 */
88 scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
89 scpi_power_on);
90}
91
92/*
93 * Helper function to get the power state of a power domain node as reported
94 * by the SCP.
95 */
96int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
97{
98 int rc, element;
99 unsigned int cpu_state, cluster_state;
100
101 /*
102 * The format of 'power_level' is implementation-defined, but 0 must
103 * mean a CPU. We also allow 1 to denote the cluster
104 */
105 if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
106 return PSCI_E_INVALID_PARAMS;
107
108 /* Query SCP */
109 rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state);
110 if (rc != 0)
111 return PSCI_E_INVALID_PARAMS;
112
113 /* Map power states of CPU and cluster to expected PSCI return codes */
114 if (power_level == ARM_PWR_LVL0) {
115 /*
116 * The CPU state returned by SCP is an 8-bit bit mask
117 * corresponding to each CPU in the cluster
118 */
119 element = mpidr & MPIDR_AFFLVL_MASK;
120 return CSS_CPU_PWR_STATE(cpu_state, element) ==
121 CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF;
122 } else {
123 assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON ||
124 cluster_state == CSS_CLUSTER_PWR_STATE_OFF);
125 return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON :
126 HW_OFF;
127 }
128}
129
130/*
131 * Helper function to shutdown the system via SCPI.
132 */
133void __dead2 css_scp_sys_shutdown(void)
134{
135 uint32_t response;
136
137 /* Send the power down request to the SCP */
138 response = scpi_sys_power_state(scpi_system_shutdown);
139
140 if (response != SCP_OK) {
141 ERROR("CSS System Off: SCP error %u.\n", response);
142 panic();
143 }
144 wfi();
145 ERROR("CSS System Off: operation not handled.\n");
146 panic();
147}
148
149/*
150 * Helper function to reset the system via SCPI.
151 */
152void __dead2 css_scp_sys_reboot(void)
153{
154 uint32_t response;
155
156 /* 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}