blob: ceb51f83e9d37ac31144111ac40295ede3dc8cbf [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
Soby Mathew74e52a72014-10-02 16:56:51 +010054 assert(psci_plat_pm_ops->affinst_off);
Achin Gupta56bcdc22014-07-28 00:15:23 +010055
Achin Gupta4f6ad662013-10-25 09:08:21 +010056 /*
57 * Plat. management: Perform platform specific actions to turn this
58 * cpu off e.g. exit cpu coherency, program the power controller etc.
59 */
Soby Mathew74e52a72014-10-02 16:56:51 +010060 psci_plat_pm_ops->affinst_off(cpu_node->level,
61 psci_get_phys_state(cpu_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +010062}
63
Soby Mathew74e52a72014-10-02 16:56:51 +010064static void psci_afflvl1_off(aff_map_node_t *cluster_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +010065{
Achin Gupta4f6ad662013-10-25 09:08:21 +010066 /* Sanity check the cluster level */
67 assert(cluster_node->level == MPIDR_AFFLVL1);
68
69 /*
Achin Gupta4f6ad662013-10-25 09:08:21 +010070 * Arch. Management. Flush all levels of caches to PoC if
Achin Guptaf6b9e992014-07-31 11:19:11 +010071 * the cluster is to be shutdown.
Achin Gupta4f6ad662013-10-25 09:08:21 +010072 */
Achin Guptaf6b9e992014-07-31 11:19:11 +010073 psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL1);
Achin Gupta4f6ad662013-10-25 09:08:21 +010074
Soby Mathew74e52a72014-10-02 16:56:51 +010075 assert(psci_plat_pm_ops->affinst_off);
Achin Gupta56bcdc22014-07-28 00:15:23 +010076
Achin Gupta4f6ad662013-10-25 09:08:21 +010077 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +000078 * Plat. Management. Allow the platform to do its cluster
Achin Gupta4f6ad662013-10-25 09:08:21 +010079 * specific bookeeping e.g. turn off interconnect coherency,
80 * program the power controller etc.
81 */
Soby Mathew74e52a72014-10-02 16:56:51 +010082 psci_plat_pm_ops->affinst_off(cluster_node->level,
Achin Gupta56bcdc22014-07-28 00:15:23 +010083 psci_get_phys_state(cluster_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +010084}
85
Soby Mathew74e52a72014-10-02 16:56:51 +010086static void psci_afflvl2_off(aff_map_node_t *system_node)
Achin Gupta4f6ad662013-10-25 09:08:21 +010087{
Achin Gupta4f6ad662013-10-25 09:08:21 +010088 /* Cannot go beyond this level */
89 assert(system_node->level == MPIDR_AFFLVL2);
90
91 /*
92 * Keep the physical state of the system handy to decide what
93 * action needs to be taken
94 */
Achin Gupta4f6ad662013-10-25 09:08:21 +010095
Achin Guptaf6b9e992014-07-31 11:19:11 +010096 /*
97 * Arch. Management. Flush all levels of caches to PoC if
98 * the system is to be shutdown.
99 */
100 psci_do_pwrdown_cache_maintenance(MPIDR_AFFLVL2);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100101
Soby Mathew74e52a72014-10-02 16:56:51 +0100102 assert(psci_plat_pm_ops->affinst_off);
Achin Gupta56bcdc22014-07-28 00:15:23 +0100103
Achin Gupta4f6ad662013-10-25 09:08:21 +0100104 /*
Achin Gupta3140a9e2013-12-02 16:23:12 +0000105 * Plat. Management : Allow the platform to do its bookeeping
Achin Gupta4f6ad662013-10-25 09:08:21 +0100106 * at this affinity level
107 */
Soby Mathew74e52a72014-10-02 16:56:51 +0100108 psci_plat_pm_ops->affinst_off(system_node->level,
Achin Gupta56bcdc22014-07-28 00:15:23 +0100109 psci_get_phys_state(system_node));
Achin Gupta4f6ad662013-10-25 09:08:21 +0100110}
111
Dan Handleye2712bc2014-04-10 15:37:22 +0100112static const afflvl_off_handler_t psci_afflvl_off_handlers[] = {
Achin Gupta4f6ad662013-10-25 09:08:21 +0100113 psci_afflvl0_off,
114 psci_afflvl1_off,
115 psci_afflvl2_off,
116};
117
118/*******************************************************************************
Achin Gupta0959db52013-12-02 17:33:04 +0000119 * This function takes an array of pointers to affinity instance nodes in the
120 * topology tree and calls the off handler for the corresponding affinity
121 * levels
122 ******************************************************************************/
Soby Mathew74e52a72014-10-02 16:56:51 +0100123static void psci_call_off_handlers(aff_map_node_t *mpidr_nodes[],
Achin Gupta0959db52013-12-02 17:33:04 +0000124 int start_afflvl,
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100125 int end_afflvl)
Achin Gupta0959db52013-12-02 17:33:04 +0000126{
Soby Mathew74e52a72014-10-02 16:56:51 +0100127 int level;
Dan Handleye2712bc2014-04-10 15:37:22 +0100128 aff_map_node_t *node;
Achin Gupta0959db52013-12-02 17:33:04 +0000129
130 for (level = start_afflvl; level <= end_afflvl; level++) {
131 node = mpidr_nodes[level];
132 if (node == NULL)
133 continue;
134
Soby Mathew74e52a72014-10-02 16:56:51 +0100135 psci_afflvl_off_handlers[level](node);
Achin Gupta0959db52013-12-02 17:33:04 +0000136 }
Achin Gupta0959db52013-12-02 17:33:04 +0000137}
138
139/*******************************************************************************
140 * Top level handler which is called when a cpu wants to power itself down.
141 * It's assumed that along with turning the cpu off, higher affinity levels will
142 * be turned off as far as possible. It traverses through all the affinity
143 * levels performing generic, architectural, platform setup and state management
144 * e.g. for a cluster that's to be powered off, it will call the platform
145 * specific code which will disable coherency at the interconnect level if the
146 * cpu is the last in the cluster. For a cpu it could mean programming the power
147 * the power controller etc.
148 *
149 * The state of all the relevant affinity levels is changed prior to calling the
150 * affinity level specific handlers as their actions would depend upon the state
151 * the affinity level is about to enter.
152 *
153 * The affinity level specific handlers are called in ascending order i.e. from
154 * the lowest to the highest affinity level implemented by the platform because
155 * to turn off affinity level X it is neccesary to turn off affinity level X - 1
156 * first.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100157 ******************************************************************************/
Andrew Thoelke2bc07852014-06-09 12:44:21 +0100158int psci_afflvl_off(int start_afflvl,
Achin Gupta0959db52013-12-02 17:33:04 +0000159 int end_afflvl)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100160{
Soby Mathew74e52a72014-10-02 16:56:51 +0100161 int rc;
Dan Handleye2712bc2014-04-10 15:37:22 +0100162 mpidr_aff_map_nodes_t mpidr_nodes;
Achin Guptaf6b9e992014-07-31 11:19:11 +0100163 unsigned int max_phys_off_afflvl;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100164
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}