blob: d5c9843a498c2272978e0d19b57be05fff8a4123 [file] [log] [blame]
Soby Mathew991d42c2015-06-29 16:30:12 +01001/*
Jeenu Viswambharan346bfd82017-01-05 11:01:02 +00002 * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
Soby Mathew991d42c2015-06-29 16:30:12 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Soby Mathew991d42c2015-06-29 16:30:12 +01005 */
6
7#include <arch.h>
8#include <arch_helpers.h>
9#include <assert.h>
10#include <bl_common.h>
Soby Mathew991d42c2015-06-29 16:30:12 +010011#include <debug.h>
12#include <context_mgmt.h>
13#include <platform.h>
Soby Mathew991d42c2015-06-29 16:30:12 +010014#include <stddef.h>
15#include "psci_private.h"
16
Soby Mathew991d42c2015-06-29 16:30:12 +010017/*******************************************************************************
18 * This function checks whether a cpu which has been requested to be turned on
19 * is OFF to begin with.
20 ******************************************************************************/
Soby Mathew85dbf5a2015-04-07 12:16:56 +010021static int cpu_on_validate_state(aff_info_state_t aff_state)
Soby Mathew991d42c2015-06-29 16:30:12 +010022{
Soby Mathew85dbf5a2015-04-07 12:16:56 +010023 if (aff_state == AFF_STATE_ON)
Soby Mathew991d42c2015-06-29 16:30:12 +010024 return PSCI_E_ALREADY_ON;
25
Soby Mathew85dbf5a2015-04-07 12:16:56 +010026 if (aff_state == AFF_STATE_ON_PENDING)
Soby Mathew991d42c2015-06-29 16:30:12 +010027 return PSCI_E_ON_PENDING;
28
Soby Mathew85dbf5a2015-04-07 12:16:56 +010029 assert(aff_state == AFF_STATE_OFF);
Soby Mathew991d42c2015-06-29 16:30:12 +010030 return PSCI_E_SUCCESS;
31}
32
33/*******************************************************************************
Soby Mathew991d42c2015-06-29 16:30:12 +010034 * Generic handler which is called to physically power on a cpu identified by
Soby Mathew6b8b3022015-06-30 11:00:24 +010035 * its mpidr. It performs the generic, architectural, platform setup and state
36 * management to power on the target cpu e.g. it will ensure that
37 * enough information is stashed for it to resume execution in the non-secure
38 * security state.
Soby Mathew991d42c2015-06-29 16:30:12 +010039 *
Soby Mathew3a9e8bf2015-05-05 16:33:16 +010040 * The state of all the relevant power domains are changed after calling the
Soby Mathew6b8b3022015-06-30 11:00:24 +010041 * platform handler as it can return error.
Soby Mathew991d42c2015-06-29 16:30:12 +010042 ******************************************************************************/
Soby Mathew011ca182015-07-29 17:05:03 +010043int psci_cpu_on_start(u_register_t target_cpu,
Sandrine Bailleux7497bff2016-04-25 09:28:43 +010044 entry_point_info_t *ep)
Soby Mathew991d42c2015-06-29 16:30:12 +010045{
46 int rc;
Soby Mathew9d754f62015-04-08 17:42:06 +010047 unsigned int target_idx = plat_core_pos_by_mpidr(target_cpu);
Soby Mathewca370502016-01-26 11:47:53 +000048 aff_info_state_t target_aff_state;
Soby Mathew991d42c2015-06-29 16:30:12 +010049
Sandrine Bailleux6181acb2016-04-22 13:00:19 +010050 /* Calling function must supply valid input arguments */
51 assert((int) target_idx >= 0);
52 assert(ep != NULL);
53
Soby Mathew991d42c2015-06-29 16:30:12 +010054 /*
55 * This function must only be called on platforms where the
56 * CPU_ON platform hooks have been implemented.
57 */
Soby Mathew3a9e8bf2015-05-05 16:33:16 +010058 assert(psci_plat_pm_ops->pwr_domain_on &&
59 psci_plat_pm_ops->pwr_domain_on_finish);
Soby Mathew991d42c2015-06-29 16:30:12 +010060
Soby Mathew9d754f62015-04-08 17:42:06 +010061 /* Protect against multiple CPUs trying to turn ON the same target CPU */
62 psci_spin_lock_cpu(target_idx);
Soby Mathew991d42c2015-06-29 16:30:12 +010063
64 /*
Soby Mathew991d42c2015-06-29 16:30:12 +010065 * Generic management: Ensure that the cpu is off to be
66 * turned on.
67 */
Soby Mathew85dbf5a2015-04-07 12:16:56 +010068 rc = cpu_on_validate_state(psci_get_aff_info_state_by_idx(target_idx));
Soby Mathew991d42c2015-06-29 16:30:12 +010069 if (rc != PSCI_E_SUCCESS)
70 goto exit;
71
72 /*
73 * Call the cpu on handler registered by the Secure Payload Dispatcher
74 * to let it do any bookeeping. If the handler encounters an error, it's
75 * expected to assert within
76 */
77 if (psci_spd_pm && psci_spd_pm->svc_on)
78 psci_spd_pm->svc_on(target_cpu);
79
80 /*
Soby Mathew85dbf5a2015-04-07 12:16:56 +010081 * Set the Affinity info state of the target cpu to ON_PENDING.
Soby Mathewca370502016-01-26 11:47:53 +000082 * Flush aff_info_state as it will be accessed with caches
83 * turned OFF.
Soby Mathew991d42c2015-06-29 16:30:12 +010084 */
Soby Mathew85dbf5a2015-04-07 12:16:56 +010085 psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_ON_PENDING);
Soby Mathewca370502016-01-26 11:47:53 +000086 flush_cpu_data_by_index(target_idx, psci_svc_cpu_data.aff_info_state);
87
88 /*
89 * The cache line invalidation by the target CPU after setting the
90 * state to OFF (see psci_do_cpu_off()), could cause the update to
91 * aff_info_state to be invalidated. Retry the update if the target
92 * CPU aff_info_state is not ON_PENDING.
93 */
94 target_aff_state = psci_get_aff_info_state_by_idx(target_idx);
95 if (target_aff_state != AFF_STATE_ON_PENDING) {
96 assert(target_aff_state == AFF_STATE_OFF);
97 psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_ON_PENDING);
98 flush_cpu_data_by_index(target_idx, psci_svc_cpu_data.aff_info_state);
99
100 assert(psci_get_aff_info_state_by_idx(target_idx) == AFF_STATE_ON_PENDING);
101 }
Soby Mathew6b8b3022015-06-30 11:00:24 +0100102
103 /*
104 * Perform generic, architecture and platform specific handling.
105 */
Soby Mathew6b8b3022015-06-30 11:00:24 +0100106 /*
107 * Plat. management: Give the platform the current state
108 * of the target cpu to allow it to perform the necessary
109 * steps to power on.
110 */
Soby Mathew011ca182015-07-29 17:05:03 +0100111 rc = psci_plat_pm_ops->pwr_domain_on(target_cpu);
Soby Mathew991d42c2015-06-29 16:30:12 +0100112 assert(rc == PSCI_E_SUCCESS || rc == PSCI_E_INTERN_FAIL);
113
114 if (rc == PSCI_E_SUCCESS)
115 /* Store the re-entry information for the non-secure world. */
Soby Mathewb0082d22015-04-09 13:40:55 +0100116 cm_init_context_by_index(target_idx, ep);
Soby Mathewca370502016-01-26 11:47:53 +0000117 else {
Soby Mathew991d42c2015-06-29 16:30:12 +0100118 /* Restore the state on error. */
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100119 psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_OFF);
Soby Mathewca370502016-01-26 11:47:53 +0000120 flush_cpu_data_by_index(target_idx, psci_svc_cpu_data.aff_info_state);
121 }
Soby Mathewb0082d22015-04-09 13:40:55 +0100122
Soby Mathew991d42c2015-06-29 16:30:12 +0100123exit:
Soby Mathew9d754f62015-04-08 17:42:06 +0100124 psci_spin_unlock_cpu(target_idx);
Soby Mathew991d42c2015-06-29 16:30:12 +0100125 return rc;
126}
127
128/*******************************************************************************
Soby Mathew3a9e8bf2015-05-05 16:33:16 +0100129 * The following function finish an earlier power on request. They
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100130 * are called by the common finisher routine in psci_common.c. The `state_info`
131 * is the psci_power_state from which this CPU has woken up from.
Soby Mathew991d42c2015-06-29 16:30:12 +0100132 ******************************************************************************/
Soby Mathew9d754f62015-04-08 17:42:06 +0100133void psci_cpu_on_finish(unsigned int cpu_idx,
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100134 psci_power_state_t *state_info)
Soby Mathew991d42c2015-06-29 16:30:12 +0100135{
Soby Mathew991d42c2015-06-29 16:30:12 +0100136 /*
137 * Plat. management: Perform the platform specific actions
138 * for this cpu e.g. enabling the gic or zeroing the mailbox
139 * register. The actual state of this cpu has already been
140 * changed.
141 */
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100142 psci_plat_pm_ops->pwr_domain_on_finish(state_info);
Soby Mathew991d42c2015-06-29 16:30:12 +0100143
Soby Mathew043fe9c2017-04-10 22:35:42 +0100144#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
Soby Mathew991d42c2015-06-29 16:30:12 +0100145 /*
146 * Arch. management: Enable data cache and manage stack memory
147 */
148 psci_do_pwrup_cache_maintenance();
Jeenu Viswambharan346bfd82017-01-05 11:01:02 +0000149#endif
Soby Mathew991d42c2015-06-29 16:30:12 +0100150
151 /*
152 * All the platform specific actions for turning this cpu
153 * on have completed. Perform enough arch.initialization
154 * to run in the non-secure address space.
155 */
Soby Mathewd0194872016-04-29 19:01:30 +0100156 psci_arch_setup();
Soby Mathew991d42c2015-06-29 16:30:12 +0100157
158 /*
Soby Mathew9d754f62015-04-08 17:42:06 +0100159 * Lock the CPU spin lock to make sure that the context initialization
160 * is done. Since the lock is only used in this function to create
161 * a synchronization point with cpu_on_start(), it can be released
162 * immediately.
163 */
164 psci_spin_lock_cpu(cpu_idx);
165 psci_spin_unlock_cpu(cpu_idx);
166
Soby Mathew85dbf5a2015-04-07 12:16:56 +0100167 /* Ensure we have been explicitly woken up by another cpu */
168 assert(psci_get_aff_info_state() == AFF_STATE_ON_PENDING);
169
Soby Mathew9d754f62015-04-08 17:42:06 +0100170 /*
Soby Mathew991d42c2015-06-29 16:30:12 +0100171 * Call the cpu on finish handler registered by the Secure Payload
172 * Dispatcher to let it do any bookeeping. If the handler encounters an
173 * error, it's expected to assert within
174 */
175 if (psci_spd_pm && psci_spd_pm->svc_on_finish)
176 psci_spd_pm->svc_on_finish(0);
177
Soby Mathew9d754f62015-04-08 17:42:06 +0100178 /* Populate the mpidr field within the cpu node array */
179 /* This needs to be done only once */
180 psci_cpu_pd_nodes[cpu_idx].mpidr = read_mpidr() & MPIDR_AFFINITY_MASK;
181
Soby Mathew991d42c2015-06-29 16:30:12 +0100182 /*
183 * Generic management: Now we just need to retrieve the
184 * information that we had stashed away during the cpu_on
185 * call to set this cpu on its way.
186 */
187 cm_prepare_el3_exit(NON_SECURE);
Soby Mathew991d42c2015-06-29 16:30:12 +0100188}