blob: 28fa52c032c3036ae4d4348fcc87f55148491c39 [file] [log] [blame]
Soby Mathew991d42c2015-06-29 16:30:12 +01001/*
Soby Mathew3a9e8bf2015-05-05 16:33:16 +01002 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
Soby Mathew991d42c2015-06-29 16:30:12 +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
31#include <arch.h>
32#include <arch_helpers.h>
33#include <assert.h>
34#include <debug.h>
Soby Mathew9d754f62015-04-08 17:42:06 +010035#include <platform.h>
Soby Mathew991d42c2015-06-29 16:30:12 +010036#include <string.h>
37#include "psci_private.h"
38
Soby Mathew6b8b3022015-06-30 11:00:24 +010039/******************************************************************************
Soby Mathew85dbf5a2015-04-07 12:16:56 +010040 * Construct the psci_power_state to request power OFF at all power levels.
41 ******************************************************************************/
42static void psci_set_power_off_state(psci_power_state_t *state_info)
43{
44 int lvl;
45
46 for (lvl = PSCI_CPU_PWR_LVL; lvl <= PLAT_MAX_PWR_LVL; lvl++)
47 state_info->pwr_domain_state[lvl] = PLAT_MAX_OFF_STATE;
48}
49
50/******************************************************************************
Soby Mathew991d42c2015-06-29 16:30:12 +010051 * Top level handler which is called when a cpu wants to power itself down.
Soby Mathew3a9e8bf2015-05-05 16:33:16 +010052 * It's assumed that along with turning the cpu power domain off, power
53 * domains at higher levels will be turned off as far as possible. It finds
54 * the highest level where a domain has to be powered off by traversing the
55 * node information and then performs generic, architectural, platform setup
56 * and state management required to turn OFF that power domain and domains
57 * below it. e.g. For a cpu that's to be powered OFF, it could mean programming
58 * the power controller whereas for a cluster that's to be powered off, it will
59 * call the platform specific code which will disable coherency at the
60 * interconnect level if the cpu is the last in the cluster and also the
61 * program the power controller.
Soby Mathew991d42c2015-06-29 16:30:12 +010062 ******************************************************************************/
Soby Mathew3a9e8bf2015-05-05 16:33:16 +010063int psci_do_cpu_off(int end_pwrlvl)
Soby Mathew991d42c2015-06-29 16:30:12 +010064{
Soby Mathew9d754f62015-04-08 17:42:06 +010065 int rc, idx = plat_my_core_pos();
Soby Mathew85dbf5a2015-04-07 12:16:56 +010066 psci_power_state_t state_info;
Soby Mathew991d42c2015-06-29 16:30:12 +010067
68 /*
69 * This function must only be called on platforms where the
70 * CPU_OFF platform hooks have been implemented.
71 */
Soby Mathew3a9e8bf2015-05-05 16:33:16 +010072 assert(psci_plat_pm_ops->pwr_domain_off);
Soby Mathew991d42c2015-06-29 16:30:12 +010073
74 /*
Soby Mathew3a9e8bf2015-05-05 16:33:16 +010075 * This function acquires the lock corresponding to each power
Soby Mathew991d42c2015-06-29 16:30:12 +010076 * level so that by the time all locks are taken, the system topology
77 * is snapshot and state management can be done safely.
78 */
Soby Mathew9d754f62015-04-08 17:42:06 +010079 psci_acquire_pwr_domain_locks(end_pwrlvl,
80 idx);
Soby Mathew991d42c2015-06-29 16:30:12 +010081
82 /*
83 * Call the cpu off handler registered by the Secure Payload Dispatcher
84 * to let it do any bookkeeping. Assume that the SPD always reports an
85 * E_DENIED error if SP refuse to power down
86 */
87 if (psci_spd_pm && psci_spd_pm->svc_off) {
88 rc = psci_spd_pm->svc_off(0);
89 if (rc)
90 goto exit;
91 }
92
Soby Mathew85dbf5a2015-04-07 12:16:56 +010093 /* Construct the psci_power_state for CPU_OFF */
94 psci_set_power_off_state(&state_info);
95
Soby Mathew991d42c2015-06-29 16:30:12 +010096 /*
Soby Mathew85dbf5a2015-04-07 12:16:56 +010097 * This function is passed the requested state info and
98 * it returns the negotiated state info for each power level upto
99 * the end level specified.
Soby Mathew991d42c2015-06-29 16:30:12 +0100100 */
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100101 psci_do_state_coordination(end_pwrlvl, &state_info);
Soby Mathew991d42c2015-06-29 16:30:12 +0100102
Soby Mathew6b8b3022015-06-30 11:00:24 +0100103 /*
104 * Arch. management. Perform the necessary steps to flush all
105 * cpu caches.
106 */
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100107 psci_do_pwrdown_cache_maintenance(psci_find_max_off_lvl(&state_info));
Soby Mathew991d42c2015-06-29 16:30:12 +0100108
109 /*
Soby Mathew6b8b3022015-06-30 11:00:24 +0100110 * Plat. management: Perform platform specific actions to turn this
111 * cpu off e.g. exit cpu coherency, program the power controller etc.
Soby Mathew991d42c2015-06-29 16:30:12 +0100112 */
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100113 psci_plat_pm_ops->pwr_domain_off(&state_info);
Soby Mathew991d42c2015-06-29 16:30:12 +0100114
115exit:
116 /*
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100117 * Release the locks corresponding to each power level in the
Soby Mathew991d42c2015-06-29 16:30:12 +0100118 * reverse order to which they were acquired.
119 */
Soby Mathew9d754f62015-04-08 17:42:06 +0100120 psci_release_pwr_domain_locks(end_pwrlvl,
121 idx);
Soby Mathew991d42c2015-06-29 16:30:12 +0100122
123 /*
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100124 * Set the affinity info state to OFF. This writes directly to main
125 * memory as caches are disabled, so cache maintenance is required
126 * to ensure that later cached reads of aff_info_state return
127 * AFF_STATE_OFF.
128 */
129 flush_cpu_data(psci_svc_cpu_data.aff_info_state);
130 psci_set_aff_info_state(AFF_STATE_OFF);
131 inv_cpu_data(psci_svc_cpu_data.aff_info_state);
132
133 /*
Soby Mathew991d42c2015-06-29 16:30:12 +0100134 * Check if all actions needed to safely power down this cpu have
135 * successfully completed. Enter a wfi loop which will allow the
136 * power controller to physically power down this cpu.
137 */
138 if (rc == PSCI_E_SUCCESS)
139 psci_power_down_wfi();
140
141 return rc;
142}