blob: e1b0ae8770b8ad9f4a9e292a6d231ebd36014896 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*
Manish Pandeyef738d12024-06-22 00:00:18 +01002 * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
Achin Gupta4f6ad662013-10-25 09:08:21 +01003 *
dp-arm82cb2c12017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Achin Gupta4f6ad662013-10-25 09:08:21 +01005 */
6
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +00007#include <assert.h>
8#include <stddef.h>
9
Dan Handley97043ac2014-04-09 13:14:54 +010010#include <arch.h>
Achin Gupta4f6ad662013-10-25 09:08:21 +010011#include <arch_helpers.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000012#include <common/bl_common.h>
Dan Handley97043ac2014-04-09 13:14:54 +010013#include <context.h>
Boyan Karatotev6bb96fa2023-01-27 09:37:07 +000014#include <lib/cpus/errata.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000015#include <lib/el3_runtime/context_mgmt.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000016#include <plat/common/platform.h>
17
Dan Handley35e98e52014-04-09 13:13:04 +010018#include "psci_private.h"
Achin Guptaef7a28c2014-02-01 08:59:56 +000019
Graeme Gregorya86865a2020-12-02 16:24:32 +000020/*
21 * Check that PLATFORM_CORE_COUNT fits into the number of cores
22 * that can be represented by PSCI_MAX_CPUS_INDEX.
23 */
24CASSERT(PLATFORM_CORE_COUNT <= (PSCI_MAX_CPUS_INDEX + 1U), assert_psci_cores_overflow);
25
Achin Guptaef7a28c2014-02-01 08:59:56 +000026/*******************************************************************************
27 * Per cpu non-secure contexts used to program the architectural state prior
28 * return to the normal world.
29 * TODO: Use the memory allocator to set aside memory for the contexts instead
Soby Mathew67487842015-07-13 14:10:57 +010030 * of relying on platform defined constants.
Achin Guptaef7a28c2014-02-01 08:59:56 +000031 ******************************************************************************/
Dan Handleyfb037bf2014-04-10 15:37:22 +010032static cpu_context_t psci_ns_context[PLATFORM_CORE_COUNT];
Manish Pandeyef738d12024-06-22 00:00:18 +010033static entry_point_info_t warmboot_ep_info[PLATFORM_CORE_COUNT];
Achin Gupta4f6ad662013-10-25 09:08:21 +010034
Soby Mathew90e82582015-01-07 11:10:22 +000035/******************************************************************************
36 * Define the psci capability variable.
37 *****************************************************************************/
Soby Mathew9d070b92015-07-29 17:05:03 +010038unsigned int psci_caps;
Soby Mathew90e82582015-01-07 11:10:22 +000039
Dan Handley7a9a5f22014-05-14 15:13:16 +010040/*******************************************************************************
Soby Mathew67487842015-07-13 14:10:57 +010041 * Function which initializes the 'psci_non_cpu_pd_nodes' or the
42 * 'psci_cpu_pd_nodes' corresponding to the power level.
Achin Gupta4f6ad662013-10-25 09:08:21 +010043 ******************************************************************************/
Graeme Gregorya86865a2020-12-02 16:24:32 +000044static void __init psci_init_pwr_domain_node(uint16_t node_idx,
Soby Mathew9d070b92015-07-29 17:05:03 +010045 unsigned int parent_idx,
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +010046 unsigned char level)
Achin Gupta4f6ad662013-10-25 09:08:21 +010047{
Soby Mathew67487842015-07-13 14:10:57 +010048 if (level > PSCI_CPU_PWR_LVL) {
Graeme Gregorya86865a2020-12-02 16:24:32 +000049 assert(node_idx < PSCI_NUM_NON_CPU_PWR_DOMAINS);
50
Soby Mathew67487842015-07-13 14:10:57 +010051 psci_non_cpu_pd_nodes[node_idx].level = level;
52 psci_lock_init(psci_non_cpu_pd_nodes, node_idx);
53 psci_non_cpu_pd_nodes[node_idx].parent_node = parent_idx;
54 psci_non_cpu_pd_nodes[node_idx].local_state =
55 PLAT_MAX_OFF_STATE;
56 } else {
57 psci_cpu_data_t *svc_cpu_data;
Achin Gupta4f6ad662013-10-25 09:08:21 +010058
Graeme Gregorya86865a2020-12-02 16:24:32 +000059 assert(node_idx < PLATFORM_CORE_COUNT);
60
Soby Mathew67487842015-07-13 14:10:57 +010061 psci_cpu_pd_nodes[node_idx].parent_node = parent_idx;
Achin Gupta4f6ad662013-10-25 09:08:21 +010062
Soby Mathew67487842015-07-13 14:10:57 +010063 /* Initialize with an invalid mpidr */
64 psci_cpu_pd_nodes[node_idx].mpidr = PSCI_INVALID_MPIDR;
Soby Mathew264999f2014-10-02 17:24:19 +010065
Soby Mathew67487842015-07-13 14:10:57 +010066 svc_cpu_data =
67 &(_cpu_data_by_index(node_idx)->psci_svc_cpu_data);
Soby Mathew264999f2014-10-02 17:24:19 +010068
Soby Mathew67487842015-07-13 14:10:57 +010069 /* Set the Affinity Info for the cores as OFF */
70 svc_cpu_data->aff_info_state = AFF_STATE_OFF;
Achin Gupta4f6ad662013-10-25 09:08:21 +010071
Boyan Karatotev0c836552024-09-30 11:31:55 +010072 /* Default to the highest power level when the cpu is not suspending */
73 svc_cpu_data->target_pwrlvl = PLAT_MAX_PWR_LVL;
Achin Gupta4f6ad662013-10-25 09:08:21 +010074
Soby Mathew67487842015-07-13 14:10:57 +010075 /* Set the power state to OFF state */
76 svc_cpu_data->local_state = PLAT_MAX_OFF_STATE;
Soby Mathew264999f2014-10-02 17:24:19 +010077
Jeenu Viswambharana10d3632017-01-06 14:58:11 +000078 psci_flush_dcache_range((uintptr_t)svc_cpu_data,
Soby Mathew67487842015-07-13 14:10:57 +010079 sizeof(*svc_cpu_data));
Achin Gupta4f6ad662013-10-25 09:08:21 +010080
Soby Mathew67487842015-07-13 14:10:57 +010081 cm_set_context_by_index(node_idx,
82 (void *) &psci_ns_context[node_idx],
Andrew Thoelke08ab89d2014-05-14 17:09:32 +010083 NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +010084 }
Achin Gupta4f6ad662013-10-25 09:08:21 +010085}
86
87/*******************************************************************************
Soby Mathew67487842015-07-13 14:10:57 +010088 * This functions updates cpu_start_idx and ncpus field for each of the node in
89 * psci_non_cpu_pd_nodes[]. It does so by comparing the parent nodes of each of
90 * the CPUs and check whether they match with the parent of the previous
91 * CPU. The basic assumption for this work is that children of the same parent
92 * are allocated adjacent indices. The platform should ensure this though proper
93 * mapping of the CPUs to indices via plat_core_pos_by_mpidr() and
94 * plat_my_core_pos() APIs.
95 *******************************************************************************/
Daniel Boulby87c85132018-09-20 14:12:46 +010096static void __init psci_update_pwrlvl_limits(void)
Achin Gupta4f6ad662013-10-25 09:08:21 +010097{
Pankaj Guptaab4df502019-10-15 15:44:45 +053098 unsigned int cpu_idx;
99 int j;
Soby Mathew67487842015-07-13 14:10:57 +0100100 unsigned int nodes_idx[PLAT_MAX_PWR_LVL] = {0};
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100101 unsigned int temp_index[PLAT_MAX_PWR_LVL];
Achin Gupta4f6ad662013-10-25 09:08:21 +0100102
Pankaj Guptaab4df502019-10-15 15:44:45 +0530103 for (cpu_idx = 0; cpu_idx < psci_plat_core_count; cpu_idx++) {
Soby Mathew67487842015-07-13 14:10:57 +0100104 psci_get_parent_pwr_domain_nodes(cpu_idx,
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600105 PLAT_MAX_PWR_LVL,
Soby Mathew67487842015-07-13 14:10:57 +0100106 temp_index);
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600107 for (j = (int)PLAT_MAX_PWR_LVL - 1; j >= 0; j--) {
Soby Mathew67487842015-07-13 14:10:57 +0100108 if (temp_index[j] != nodes_idx[j]) {
109 nodes_idx[j] = temp_index[j];
110 psci_non_cpu_pd_nodes[nodes_idx[j]].cpu_start_idx
111 = cpu_idx;
112 }
113 psci_non_cpu_pd_nodes[nodes_idx[j]].ncpus++;
114 }
115 }
116}
117
Manish Pandeyef738d12024-06-22 00:00:18 +0100118static void __init populate_cpu_data(void)
119{
120 for (unsigned int idx = 0; idx < psci_plat_core_count; idx++) {
121 set_cpu_data_by_index(idx, warmboot_ep_info, &warmboot_ep_info[idx]);
122 }
123}
124
Soby Mathew67487842015-07-13 14:10:57 +0100125/*******************************************************************************
126 * Core routine to populate the power domain tree. The tree descriptor passed by
127 * the platform is populated breadth-first and the first entry in the map
128 * informs the number of root power domains. The parent nodes of the root nodes
129 * will point to an invalid entry(-1).
130 ******************************************************************************/
Pankaj Guptaab4df502019-10-15 15:44:45 +0530131static unsigned int __init populate_power_domain_tree(const unsigned char
132 *topology)
Soby Mathew67487842015-07-13 14:10:57 +0100133{
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100134 unsigned int i, j = 0U, num_nodes_at_lvl = 1U, num_nodes_at_next_lvl;
135 unsigned int node_index = 0U, num_children;
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600136 unsigned int parent_node_index = 0U;
137 int level = (int)PLAT_MAX_PWR_LVL;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100138
139 /*
Soby Mathew67487842015-07-13 14:10:57 +0100140 * For each level the inputs are:
141 * - number of nodes at this level in plat_array i.e. num_nodes_at_level
142 * This is the sum of values of nodes at the parent level.
143 * - Index of first entry at this level in the plat_array i.e.
144 * parent_node_index.
145 * - Index of first free entry in psci_non_cpu_pd_nodes[] or
146 * psci_cpu_pd_nodes[] i.e. node_index depending upon the level.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100147 */
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100148 while (level >= (int) PSCI_CPU_PWR_LVL) {
149 num_nodes_at_next_lvl = 0U;
Soby Mathew67487842015-07-13 14:10:57 +0100150 /*
151 * For each entry (parent node) at this level in the plat_array:
152 * - Find the number of children
153 * - Allocate a node in a power domain array for each child
154 * - Set the parent of the child to the parent_node_index - 1
155 * - Increment parent_node_index to point to the next parent
156 * - Accumulate the number of children at next level.
157 */
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100158 for (i = 0U; i < num_nodes_at_lvl; i++) {
Soby Mathew67487842015-07-13 14:10:57 +0100159 assert(parent_node_index <=
160 PSCI_NUM_NON_CPU_PWR_DOMAINS);
161 num_children = topology[parent_node_index];
Achin Gupta4f6ad662013-10-25 09:08:21 +0100162
Soby Mathew67487842015-07-13 14:10:57 +0100163 for (j = node_index;
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100164 j < (node_index + num_children); j++)
Graeme Gregorya86865a2020-12-02 16:24:32 +0000165 psci_init_pwr_domain_node((uint16_t)j,
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600166 parent_node_index - 1U,
167 (unsigned char)level);
Soby Mathew67487842015-07-13 14:10:57 +0100168
169 node_index = j;
170 num_nodes_at_next_lvl += num_children;
171 parent_node_index++;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100172 }
173
Soby Mathew67487842015-07-13 14:10:57 +0100174 num_nodes_at_lvl = num_nodes_at_next_lvl;
175 level--;
176
177 /* Reset the index for the cpu power domain array */
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100178 if (level == (int) PSCI_CPU_PWR_LVL)
Soby Mathew67487842015-07-13 14:10:57 +0100179 node_index = 0;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100180 }
181
Soby Mathew67487842015-07-13 14:10:57 +0100182 /* Validate the sanity of array exported by the platform */
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600183 assert(j <= PLATFORM_CORE_COUNT);
Pankaj Guptaab4df502019-10-15 15:44:45 +0530184 return j;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100185}
186
187/*******************************************************************************
Soby Mathewcf0b1492016-04-29 19:01:30 +0100188 * This function does the architectural setup and takes the warm boot
189 * entry-point `mailbox_ep` as an argument. The function also initializes the
190 * power domain topology tree by querying the platform. The power domain nodes
191 * higher than the CPU are populated in the array psci_non_cpu_pd_nodes[] and
192 * the CPU power domains are populated in psci_cpu_pd_nodes[]. The platform
193 * exports its static topology map through the
Soby Mathew67487842015-07-13 14:10:57 +0100194 * populate_power_domain_topology_tree() API. The algorithm populates the
195 * psci_non_cpu_pd_nodes and psci_cpu_pd_nodes iteratively by using this
Soby Mathewcf0b1492016-04-29 19:01:30 +0100196 * topology map. On a platform that implements two clusters of 2 cpus each,
197 * and supporting 3 domain levels, the populated psci_non_cpu_pd_nodes would
198 * look like this:
Achin Gupta4f6ad662013-10-25 09:08:21 +0100199 *
Achin Gupta4f6ad662013-10-25 09:08:21 +0100200 * ---------------------------------------------------
Soby Mathew67487842015-07-13 14:10:57 +0100201 * | system node | cluster 0 node | cluster 1 node |
Achin Gupta4f6ad662013-10-25 09:08:21 +0100202 * ---------------------------------------------------
Achin Gupta4f6ad662013-10-25 09:08:21 +0100203 *
Soby Mathew67487842015-07-13 14:10:57 +0100204 * And populated psci_cpu_pd_nodes would look like this :
205 * <- cpus cluster0 -><- cpus cluster1 ->
206 * ------------------------------------------------
207 * | CPU 0 | CPU 1 | CPU 2 | CPU 3 |
208 * ------------------------------------------------
Achin Gupta4f6ad662013-10-25 09:08:21 +0100209 ******************************************************************************/
Daniel Boulby87c85132018-09-20 14:12:46 +0100210int __init psci_setup(const psci_lib_args_t *lib_args)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100211{
Soby Mathew67487842015-07-13 14:10:57 +0100212 const unsigned char *topology_tree;
Boyan Karatotev3b802102024-11-06 16:26:15 +0000213 unsigned int cpu_idx = plat_my_core_pos();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100214
Soby Mathewf426fc02016-09-13 14:19:08 +0100215 assert(VERIFY_PSCI_LIB_ARGS_V1(lib_args));
216
Soby Mathewcf0b1492016-04-29 19:01:30 +0100217 /* Do the Architectural initialization */
218 psci_arch_setup();
219
Soby Mathew67487842015-07-13 14:10:57 +0100220 /* Query the topology map from the platform */
221 topology_tree = plat_get_power_domain_tree_desc();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100222
Soby Mathew67487842015-07-13 14:10:57 +0100223 /* Populate the power domain arrays using the platform topology map */
Pankaj Guptaab4df502019-10-15 15:44:45 +0530224 psci_plat_core_count = populate_power_domain_tree(topology_tree);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100225
Soby Mathew67487842015-07-13 14:10:57 +0100226 /* Update the CPU limits for each node in psci_non_cpu_pd_nodes */
227 psci_update_pwrlvl_limits();
228
Manish Pandeyef738d12024-06-22 00:00:18 +0100229 /* Initialise the warmboot entrypoints */
230 populate_cpu_data();
231
Soby Mathew67487842015-07-13 14:10:57 +0100232 /* Populate the mpidr field of cpu node for this CPU */
Boyan Karatotev3b802102024-11-06 16:26:15 +0000233 psci_cpu_pd_nodes[cpu_idx].mpidr =
Soby Mathew67487842015-07-13 14:10:57 +0100234 read_mpidr() & MPIDR_AFFINITY_MASK;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100235
Soby Mathew67487842015-07-13 14:10:57 +0100236 psci_init_req_local_pwr_states();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100237
238 /*
Soby Mathew67487842015-07-13 14:10:57 +0100239 * Set the requested and target state of this CPU and all the higher
240 * power domain levels for this CPU to run.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100241 */
Boyan Karatotev3b802102024-11-06 16:26:15 +0000242 psci_set_pwr_domains_to_run(cpu_idx, PLAT_MAX_PWR_LVL);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100243
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100244 (void) plat_setup_psci_ops((uintptr_t)lib_args->mailbox_ep,
245 &psci_plat_pm_ops);
246 assert(psci_plat_pm_ops != NULL);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100247
Soby Mathew7a3d4bd2016-09-09 11:33:58 +0100248 /*
249 * Flush `psci_plat_pm_ops` as it will be accessed by secondary CPUs
Jeenu Viswambharana10d3632017-01-06 14:58:11 +0000250 * during warm boot, possibly before data cache is enabled.
Soby Mathew7a3d4bd2016-09-09 11:33:58 +0100251 */
Jeenu Viswambharana10d3632017-01-06 14:58:11 +0000252 psci_flush_dcache_range((uintptr_t)&psci_plat_pm_ops,
Soby Mathew7a3d4bd2016-09-09 11:33:58 +0100253 sizeof(psci_plat_pm_ops));
254
Soby Mathew90e82582015-01-07 11:10:22 +0000255 /* Initialize the psci capability */
256 psci_caps = PSCI_GENERIC_CAP;
257
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530258 if (psci_plat_pm_ops->pwr_domain_off != NULL) {
Soby Mathew90e82582015-01-07 11:10:22 +0000259 psci_caps |= define_psci_cap(PSCI_CPU_OFF);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530260 }
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100261 if ((psci_plat_pm_ops->pwr_domain_on != NULL) &&
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530262 (psci_plat_pm_ops->pwr_domain_on_finish != NULL)) {
Soby Mathew90e82582015-01-07 11:10:22 +0000263 psci_caps |= define_psci_cap(PSCI_CPU_ON_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530264 }
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100265 if ((psci_plat_pm_ops->pwr_domain_suspend != NULL) &&
266 (psci_plat_pm_ops->pwr_domain_suspend_finish != NULL)) {
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530267 if (psci_plat_pm_ops->validate_power_state != NULL) {
Samuel Hollanda1d5ac62021-04-28 17:52:02 -0500268 psci_caps |= define_psci_cap(PSCI_CPU_SUSPEND_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530269 }
270 if (psci_plat_pm_ops->get_sys_suspend_power_state != NULL) {
Soby Mathewc0aff0e2014-12-17 14:47:57 +0000271 psci_caps |= define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530272 }
Wing Lib88a4412022-09-14 13:18:15 -0700273#if PSCI_OS_INIT_MODE
274 psci_caps |= define_psci_cap(PSCI_SET_SUSPEND_MODE);
275#endif
Soby Mathewc0aff0e2014-12-17 14:47:57 +0000276 }
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530277 if (psci_plat_pm_ops->system_off != NULL) {
Soby Mathew90e82582015-01-07 11:10:22 +0000278 psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530279 }
280 if (psci_plat_pm_ops->system_reset != NULL) {
Soby Mathew90e82582015-01-07 11:10:22 +0000281 psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530282 }
283 if (psci_plat_pm_ops->get_node_hw_state != NULL) {
Jeenu Viswambharan28d3d612016-08-03 15:54:50 +0100284 psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530285 }
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100286 if ((psci_plat_pm_ops->read_mem_protect != NULL) &&
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530287 (psci_plat_pm_ops->write_mem_protect != NULL)) {
Roberto Vargasd4c596b2017-08-03 08:16:16 +0100288 psci_caps |= define_psci_cap(PSCI_MEM_PROTECT);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530289 }
290 if (psci_plat_pm_ops->mem_protect_chk != NULL) {
Roberto Vargasd4c596b2017-08-03 08:16:16 +0100291 psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530292 }
293 if (psci_plat_pm_ops->system_reset2 != NULL) {
Roberto Vargas36a8f8f2017-07-26 09:23:09 +0100294 psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530295 }
Yatharth Kochar170fb932016-05-09 18:26:35 +0100296#if ENABLE_PSCI_STAT
297 psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
298 psci_caps |= define_psci_cap(PSCI_STAT_COUNT_AARCH64);
299#endif
300
Achin Gupta7421b462014-02-01 18:53:26 +0000301 return 0;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100302}
Soby Mathewcf0b1492016-04-29 19:01:30 +0100303
304/*******************************************************************************
305 * This duplicates what the primary cpu did after a cold boot in BL1. The same
306 * needs to be done when a cpu is hotplugged in. This function could also over-
307 * ride any EL3 setup done by BL1 as this code resides in rw memory.
308 ******************************************************************************/
309void psci_arch_setup(void)
310{
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100311#if (ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_GENERIC_TIMER)
Soby Mathewcf0b1492016-04-29 19:01:30 +0100312 /* Program the counter frequency */
313 write_cntfrq_el0(plat_get_syscnt_freq2());
Etienne Carriere86e26832017-11-08 14:41:47 +0100314#endif
Soby Mathewcf0b1492016-04-29 19:01:30 +0100315
316 /* Initialize the cpu_ops pointer. */
317 init_cpu_ops();
Jeenu Viswambharan10bcd762017-01-03 11:01:51 +0000318
319 /* Having initialized cpu_ops, we can now print errata status */
320 print_errata_status();
Alexei Fedoroved108b52019-09-13 14:11:59 +0100321
322#if ENABLE_PAUTH
323 /* Store APIAKey_EL1 key */
324 set_cpu_data(apiakey[0], read_apiakeylo_el1());
325 set_cpu_data(apiakey[1], read_apiakeyhi_el1());
326#endif /* ENABLE_PAUTH */
Soby Mathewcf0b1492016-04-29 19:01:30 +0100327}
Soby Mathew727e5232016-05-05 14:11:23 +0100328
329/******************************************************************************
330 * PSCI Library interface to initialize the cpu context for the next non
331 * secure image during cold boot. The relevant registers in the cpu context
332 * need to be retrieved and programmed on return from this interface.
333 *****************************************************************************/
334void psci_prepare_next_non_secure_ctx(entry_point_info_t *next_image_info)
335{
336 assert(GET_SECURITY_STATE(next_image_info->h.attr) == NON_SECURE);
337 cm_init_my_context(next_image_info);
338 cm_prepare_el3_exit(NON_SECURE);
339}