blob: 7eb968899eaf7dd1fc3c5d828959b17eb05482ed [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Dan Handleye83b0ca2014-01-14 18:17:09 +00002 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
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
Dan Handley2bd4ef22014-04-09 13:14:54 +010031#include <arch.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010032#include <arch_helpers.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010033#include <assert.h>
Soby Mathew74e52a72014-10-02 16:56:51 +010034#include <debug.h>
Dan Handley2bd4ef22014-04-09 13:14:54 +010035#include <string.h>
Dan Handley714a0d22014-04-09 13:13:04 +010036#include "psci_private.h"
Achin Gupta4f6ad662013-10-25 09:08:21 +010037
Soby Mathew74e52a72014-10-02 16:56:51 +010038typedef void (*afflvl_off_handler_t)(aff_map_node_t *node);
Achin Gupta4f6ad662013-10-25 09:08:21 +010039
40/*******************************************************************************
41 * The next three functions implement a handler for each supported affinity
42 * level which is called when that affinity level is turned off.
43 ******************************************************************************/
Soby Mathew74e52a72014-10-02 16:56:51 +010044static void psci_afflvl0_off(aff_map_node_t *cpu_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +010045{
Achin Gupta4f6ad662013-10-25 09:08:21 +010046 assert(cpu_node->level == MPIDR_AFFLVL0);
47
48 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +010049 * Arch. management. Perform the necessary steps to flush all
50 * cpu caches.
Achin Gupta4f6ad662013-10-25 09:08:21 +010051 */
Achin Guptae1aa5162014-06-26 09:58:52 +010052 psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL0);
Achin Gupta4f6ad662013-10-25 09:08:21 +010053
54 /*
55 * Plat. management: Perform platform specific actions to turn this
56 * cpu off e.g. exit cpu coherency, program the power controller etc.
57 */
Soby Mathew74e52a72014-10-02 16:56:51 +010058 psci_plat_pm_ops->affinst_off(cpu_node->level,
59 psci_get_phys_state(cpu_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +010060}
61
Soby Mathew74e52a72014-10-02 16:56:51 +010062static void psci_afflvl1_off(aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +010063{
Achin Gupta4f6ad662013-10-25 09:08:21 +010064 /* Sanity check the cluster level */
65 assert(cluster_node->level == MPIDR_AFFLVL1);
66
67 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +010068 * Arch. Management. Flush all levels of caches to PoC if
Achin Guptaf6b9e992014-07-31 11:19:11 +010069 * the cluster is to be shutdown.
Achin Gupta4f6ad662013-10-25 09:08:21 +010070 */
Achin Guptaf6b9e992014-07-31 11:19:11 +010071 psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1);
Achin Gupta4f6ad662013-10-25 09:08:21 +010072
73 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +000074 * Plat. Management. Allow the platform to do its cluster
Achin Gupta4f6ad662013-10-25 09:08:21 +010075 * specific bookeeping e.g. turn off interconnect coherency,
76 * program the power controller etc.
77 */
Soby Mathew74e52a72014-10-02 16:56:51 +010078 psci_plat_pm_ops->affinst_off(cluster_node->level,
Achin Gupta56bcdc22014-07-28 00:15:23 +010079 psci_get_phys_state(cluster_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +010080}
81
Soby Mathew74e52a72014-10-02 16:56:51 +010082static void psci_afflvl2_off(aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +010083{
Achin Gupta4f6ad662013-10-25 09:08:21 +010084 /* Cannot go beyond this level */
85 assert(system_node->level == MPIDR_AFFLVL2);
86
87 /*
88 * Keep the physical state of the system handy to decide what
89 * action needs to be taken
90 */
Achin Gupta4f6ad662013-10-25 09:08:21 +010091
Achin Guptaf6b9e992014-07-31 11:19:11 +010092 /*
93 * Arch. Management. Flush all levels of caches to PoC if
94 * the system is to be shutdown.
95 */
96 psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2);
Achin Gupta4f6ad662013-10-25 09:08:21 +010097
98 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +000099 * Plat. Management : Allow the platform to do its bookeeping
Achin Gupta4f6ad662013-10-25 09:08:21 +0100100 * at this affinity level
101 */
Soby Mathew74e52a72014-10-02 16:56:51 +0100102 psci_plat_pm_ops->affinst_off(system_node->level,
Achin Gupta56bcdc22014-07-28 00:15:23 +0100103 psci_get_phys_state(system_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100104}
105
Dan Handleye2712bc2014-04-10 15:37:22 +0100106static const afflvl_off_handler_t psci_afflvl_off_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100107 psci_afflvl0_off,
108 psci_afflvl1_off,
109 psci_afflvl2_off,
110};
111
112/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000113 * This function takes an array of pointers to affinity instance nodes in the
114 * topology tree and calls the off handler for the corresponding affinity
115 * levels
116 ******************************************************************************/
Soby Mathew74e52a72014-10-02 16:56:51 +0100117static void psci_call_off_handlers(aff_map_node_t *mpidr_nodes[],
Achin Gupta0959db52013-12-02 17:33:04 +0000118 int start_afflvl,
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100119 int end_afflvl)
Achin Gupta0959db52013-12-02 17:33:04 +0000120{
Soby Mathew74e52a72014-10-02 16:56:51 +0100121 int level;
Dan Handleye2712bc2014-04-10 15:37:22 +0100122 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000123
124 for (level = start_afflvl; level <= end_afflvl; level++) {
125 node = mpidr_nodes[level];
126 if (node == NULL)
127 continue;
128
Soby Mathew74e52a72014-10-02 16:56:51 +0100129 psci_afflvl_off_handlers[level](node);
Achin Gupta0959db52013-12-02 17:33:04 +0000130 }
Achin Gupta0959db52013-12-02 17:33:04 +0000131}
132
133/*******************************************************************************
134 * Top level handler which is called when a cpu wants to power itself down.
135 * It's assumed that along with turning the cpu off, higher affinity levels will
136 * be turned off as far as possible. It traverses through all the affinity
137 * levels performing generic, architectural, platform setup and state management
138 * e.g. for a cluster that's to be powered off, it will call the platform
139 * specific code which will disable coherency at the interconnect level if the
140 * cpu is the last in the cluster. For a cpu it could mean programming the power
141 * the power controller etc.
142 *
143 * The state of all the relevant affinity levels is changed prior to calling the
144 * affinity level specific handlers as their actions would depend upon the state
145 * the affinity level is about to enter.
146 *
147 * The affinity level specific handlers are called in ascending order i.e. from
148 * the lowest to the highest affinity level implemented by the platform because
149 * to turn off affinity level X it is neccesary to turn off affinity level X - 1
150 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100151 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100152int psci_afflvl_off(int start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000153 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100154{
Soby Mathew74e52a72014-10-02 16:56:51 +0100155 int rc;
Dan Handleye2712bc2014-04-10 15:37:22 +0100156 mpidr_aff_map_nodes_t mpidr_nodes;
Achin Guptaf6b9e992014-07-31 11:19:11 +0100157 unsigned int max_phys_off_afflvl;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100158
159 /*
Soby Mathew61e615b2015-01-15 11:49:49 +0000160 * This function must only be called on platforms where the
161 * CPU_OFF platform hooks have been implemented.
162 */
163 assert(psci_plat_pm_ops->affinst_off);
164
165 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000166 * Collect the pointers to the nodes in the topology tree for
167 * each affinity instance in the mpidr. If this function does
168 * not return successfully then either the mpidr or the affinity
Soby Mathew74e52a72014-10-02 16:56:51 +0100169 * levels are incorrect. Either way, this an internal TF error
170 * therefore assert.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100171 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100172 rc = psci_get_aff_map_nodes(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
Achin Gupta0959db52013-12-02 17:33:04 +0000173 start_afflvl,
174 end_afflvl,
175 mpidr_nodes);
Soby Mathew74e52a72014-10-02 16:56:51 +0100176 assert(rc == PSCI_E_SUCCESS);
Achin Gupta0959db52013-12-02 17:33:04 +0000177
Achin Gupta4f6ad662013-10-25 09:08:21 +0100178 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000179 * This function acquires the lock corresponding to each affinity
180 * level so that by the time all locks are taken, the system topology
181 * is snapshot and state management can be done safely.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100182 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100183 psci_acquire_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000184 end_afflvl,
185 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100186
Soby Mathew74e52a72014-10-02 16:56:51 +0100187
188 /*
189 * Call the cpu off handler registered by the Secure Payload Dispatcher
190 * to let it do any bookkeeping. Assume that the SPD always reports an
191 * E_DENIED error if SP refuse to power down
192 */
193 if (psci_spd_pm && psci_spd_pm->svc_off) {
194 rc = psci_spd_pm->svc_off(0);
195 if (rc)
196 goto exit;
197 }
198
Achin Guptacab78e42014-07-28 00:09:01 +0100199 /*
200 * This function updates the state of each affinity instance
201 * corresponding to the mpidr in the range of affinity levels
202 * specified.
203 */
204 psci_do_afflvl_state_mgmt(start_afflvl,
205 end_afflvl,
206 mpidr_nodes,
207 PSCI_STATE_OFF);
Achin Guptaf6b9e992014-07-31 11:19:11 +0100208
209 max_phys_off_afflvl = psci_find_max_phys_off_afflvl(start_afflvl,
210 end_afflvl,
211 mpidr_nodes);
212 assert(max_phys_off_afflvl != PSCI_INVALID_DATA);
213
214 /* Stash the highest affinity level that will enter the OFF state. */
215 psci_set_max_phys_off_afflvl(max_phys_off_afflvl);
216
Achin Gupta0959db52013-12-02 17:33:04 +0000217 /* Perform generic, architecture and platform specific handling */
Soby Mathew74e52a72014-10-02 16:56:51 +0100218 psci_call_off_handlers(mpidr_nodes,
Achin Gupta0959db52013-12-02 17:33:04 +0000219 start_afflvl,
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100220 end_afflvl);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100221
222 /*
Achin Guptaf6b9e992014-07-31 11:19:11 +0100223 * Invalidate the entry for the highest affinity level stashed earlier.
224 * This ensures that any reads of this variable outside the power
225 * up/down sequences return PSCI_INVALID_DATA.
226 *
227 */
228 psci_set_max_phys_off_afflvl(PSCI_INVALID_DATA);
229
Soby Mathew74e52a72014-10-02 16:56:51 +0100230exit:
Achin Guptaf6b9e992014-07-31 11:19:11 +0100231 /*
Achin Gupta0959db52013-12-02 17:33:04 +0000232 * Release the locks corresponding to each affinity level in the
233 * reverse order to which they were acquired.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100234 */
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100235 psci_release_afflvl_locks(start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000236 end_afflvl,
237 mpidr_nodes);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100238
Soby Mathew26fb90e2015-01-06 21:36:55 +0000239 /*
240 * Check if all actions needed to safely power down this cpu have
241 * successfully completed. Enter a wfi loop which will allow the
242 * power controller to physically power down this cpu.
243 */
244 if (rc == PSCI_E_SUCCESS)
245 psci_power_down_wfi();
246
Achin Gupta4f6ad662013-10-25 09:08:21 +0100247 return rc;
248}