blob: 44c9bdb9a11762d2bf4382230ee06ceea086c1bf [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
Boyan Karatotevd43b2ea2025-03-18 10:31:22 +000066 svc_cpu_data = &get_cpu_data_by_index(node_idx, psci_svc_cpu_data);
Soby Mathew264999f2014-10-02 17:24:19 +010067
Soby Mathew67487842015-07-13 14:10:57 +010068 /* Set the Affinity Info for the cores as OFF */
69 svc_cpu_data->aff_info_state = AFF_STATE_OFF;
Achin Gupta4f6ad662013-10-25 09:08:21 +010070
Boyan Karatotev0c836552024-09-30 11:31:55 +010071 /* Default to the highest power level when the cpu is not suspending */
72 svc_cpu_data->target_pwrlvl = PLAT_MAX_PWR_LVL;
Achin Gupta4f6ad662013-10-25 09:08:21 +010073
Soby Mathew67487842015-07-13 14:10:57 +010074 /* Set the power state to OFF state */
75 svc_cpu_data->local_state = PLAT_MAX_OFF_STATE;
Soby Mathew264999f2014-10-02 17:24:19 +010076
Jeenu Viswambharana10d3632017-01-06 14:58:11 +000077 psci_flush_dcache_range((uintptr_t)svc_cpu_data,
Soby Mathew67487842015-07-13 14:10:57 +010078 sizeof(*svc_cpu_data));
Achin Gupta4f6ad662013-10-25 09:08:21 +010079
Soby Mathew67487842015-07-13 14:10:57 +010080 cm_set_context_by_index(node_idx,
81 (void *) &psci_ns_context[node_idx],
Andrew Thoelke08ab89d2014-05-14 17:09:32 +010082 NON_SECURE);
Achin Gupta4f6ad662013-10-25 09:08:21 +010083 }
Achin Gupta4f6ad662013-10-25 09:08:21 +010084}
85
86/*******************************************************************************
Soby Mathew67487842015-07-13 14:10:57 +010087 * This functions updates cpu_start_idx and ncpus field for each of the node in
88 * psci_non_cpu_pd_nodes[]. It does so by comparing the parent nodes of each of
89 * the CPUs and check whether they match with the parent of the previous
90 * CPU. The basic assumption for this work is that children of the same parent
91 * are allocated adjacent indices. The platform should ensure this though proper
92 * mapping of the CPUs to indices via plat_core_pos_by_mpidr() and
93 * plat_my_core_pos() APIs.
94 *******************************************************************************/
Daniel Boulby87c85132018-09-20 14:12:46 +010095static void __init psci_update_pwrlvl_limits(void)
Achin Gupta4f6ad662013-10-25 09:08:21 +010096{
Pankaj Guptaab4df502019-10-15 15:44:45 +053097 unsigned int cpu_idx;
98 int j;
Soby Mathew67487842015-07-13 14:10:57 +010099 unsigned int nodes_idx[PLAT_MAX_PWR_LVL] = {0};
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100100 unsigned int temp_index[PLAT_MAX_PWR_LVL];
Achin Gupta4f6ad662013-10-25 09:08:21 +0100101
Pankaj Guptaab4df502019-10-15 15:44:45 +0530102 for (cpu_idx = 0; cpu_idx < psci_plat_core_count; cpu_idx++) {
Soby Mathew67487842015-07-13 14:10:57 +0100103 psci_get_parent_pwr_domain_nodes(cpu_idx,
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600104 PLAT_MAX_PWR_LVL,
Soby Mathew67487842015-07-13 14:10:57 +0100105 temp_index);
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600106 for (j = (int)PLAT_MAX_PWR_LVL - 1; j >= 0; j--) {
Soby Mathew67487842015-07-13 14:10:57 +0100107 if (temp_index[j] != nodes_idx[j]) {
108 nodes_idx[j] = temp_index[j];
109 psci_non_cpu_pd_nodes[nodes_idx[j]].cpu_start_idx
110 = cpu_idx;
111 }
112 psci_non_cpu_pd_nodes[nodes_idx[j]].ncpus++;
113 }
114 }
115}
116
Manish Pandeyef738d12024-06-22 00:00:18 +0100117static void __init populate_cpu_data(void)
118{
119 for (unsigned int idx = 0; idx < psci_plat_core_count; idx++) {
120 set_cpu_data_by_index(idx, warmboot_ep_info, &warmboot_ep_info[idx]);
121 }
122}
123
Soby Mathew67487842015-07-13 14:10:57 +0100124/*******************************************************************************
125 * Core routine to populate the power domain tree. The tree descriptor passed by
126 * the platform is populated breadth-first and the first entry in the map
127 * informs the number of root power domains. The parent nodes of the root nodes
128 * will point to an invalid entry(-1).
129 ******************************************************************************/
Pankaj Guptaab4df502019-10-15 15:44:45 +0530130static unsigned int __init populate_power_domain_tree(const unsigned char
131 *topology)
Soby Mathew67487842015-07-13 14:10:57 +0100132{
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100133 unsigned int i, j = 0U, num_nodes_at_lvl = 1U, num_nodes_at_next_lvl;
134 unsigned int node_index = 0U, num_children;
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600135 unsigned int parent_node_index = 0U;
136 int level = (int)PLAT_MAX_PWR_LVL;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100137
138 /*
Soby Mathew67487842015-07-13 14:10:57 +0100139 * For each level the inputs are:
140 * - number of nodes at this level in plat_array i.e. num_nodes_at_level
141 * This is the sum of values of nodes at the parent level.
142 * - Index of first entry at this level in the plat_array i.e.
143 * parent_node_index.
144 * - Index of first free entry in psci_non_cpu_pd_nodes[] or
145 * psci_cpu_pd_nodes[] i.e. node_index depending upon the level.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100146 */
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100147 while (level >= (int) PSCI_CPU_PWR_LVL) {
148 num_nodes_at_next_lvl = 0U;
Soby Mathew67487842015-07-13 14:10:57 +0100149 /*
150 * For each entry (parent node) at this level in the plat_array:
151 * - Find the number of children
152 * - Allocate a node in a power domain array for each child
153 * - Set the parent of the child to the parent_node_index - 1
154 * - Increment parent_node_index to point to the next parent
155 * - Accumulate the number of children at next level.
156 */
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100157 for (i = 0U; i < num_nodes_at_lvl; i++) {
Soby Mathew67487842015-07-13 14:10:57 +0100158 assert(parent_node_index <=
159 PSCI_NUM_NON_CPU_PWR_DOMAINS);
160 num_children = topology[parent_node_index];
Achin Gupta4f6ad662013-10-25 09:08:21 +0100161
Soby Mathew67487842015-07-13 14:10:57 +0100162 for (j = node_index;
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100163 j < (node_index + num_children); j++)
Graeme Gregorya86865a2020-12-02 16:24:32 +0000164 psci_init_pwr_domain_node((uint16_t)j,
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600165 parent_node_index - 1U,
166 (unsigned char)level);
Soby Mathew67487842015-07-13 14:10:57 +0100167
168 node_index = j;
169 num_nodes_at_next_lvl += num_children;
170 parent_node_index++;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100171 }
172
Soby Mathew67487842015-07-13 14:10:57 +0100173 num_nodes_at_lvl = num_nodes_at_next_lvl;
174 level--;
175
176 /* Reset the index for the cpu power domain array */
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100177 if (level == (int) PSCI_CPU_PWR_LVL)
Soby Mathew67487842015-07-13 14:10:57 +0100178 node_index = 0;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100179 }
180
Soby Mathew67487842015-07-13 14:10:57 +0100181 /* Validate the sanity of array exported by the platform */
Deepika Bhavnani5b33ad12019-12-13 10:23:18 -0600182 assert(j <= PLATFORM_CORE_COUNT);
Pankaj Guptaab4df502019-10-15 15:44:45 +0530183 return j;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100184}
185
186/*******************************************************************************
Soby Mathewcf0b1492016-04-29 19:01:30 +0100187 * This function does the architectural setup and takes the warm boot
188 * entry-point `mailbox_ep` as an argument. The function also initializes the
189 * power domain topology tree by querying the platform. The power domain nodes
190 * higher than the CPU are populated in the array psci_non_cpu_pd_nodes[] and
191 * the CPU power domains are populated in psci_cpu_pd_nodes[]. The platform
192 * exports its static topology map through the
Soby Mathew67487842015-07-13 14:10:57 +0100193 * populate_power_domain_topology_tree() API. The algorithm populates the
194 * psci_non_cpu_pd_nodes and psci_cpu_pd_nodes iteratively by using this
Soby Mathewcf0b1492016-04-29 19:01:30 +0100195 * topology map. On a platform that implements two clusters of 2 cpus each,
196 * and supporting 3 domain levels, the populated psci_non_cpu_pd_nodes would
197 * look like this:
Achin Gupta4f6ad662013-10-25 09:08:21 +0100198 *
Achin Gupta4f6ad662013-10-25 09:08:21 +0100199 * ---------------------------------------------------
Soby Mathew67487842015-07-13 14:10:57 +0100200 * | system node | cluster 0 node | cluster 1 node |
Achin Gupta4f6ad662013-10-25 09:08:21 +0100201 * ---------------------------------------------------
Achin Gupta4f6ad662013-10-25 09:08:21 +0100202 *
Soby Mathew67487842015-07-13 14:10:57 +0100203 * And populated psci_cpu_pd_nodes would look like this :
204 * <- cpus cluster0 -><- cpus cluster1 ->
205 * ------------------------------------------------
206 * | CPU 0 | CPU 1 | CPU 2 | CPU 3 |
207 * ------------------------------------------------
Achin Gupta4f6ad662013-10-25 09:08:21 +0100208 ******************************************************************************/
Daniel Boulby87c85132018-09-20 14:12:46 +0100209int __init psci_setup(const psci_lib_args_t *lib_args)
Achin Gupta4f6ad662013-10-25 09:08:21 +0100210{
Soby Mathew67487842015-07-13 14:10:57 +0100211 const unsigned char *topology_tree;
Boyan Karatotev3b802102024-11-06 16:26:15 +0000212 unsigned int cpu_idx = plat_my_core_pos();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100213
Soby Mathewf426fc02016-09-13 14:19:08 +0100214 assert(VERIFY_PSCI_LIB_ARGS_V1(lib_args));
215
Soby Mathewcf0b1492016-04-29 19:01:30 +0100216 /* Do the Architectural initialization */
217 psci_arch_setup();
218
Soby Mathew67487842015-07-13 14:10:57 +0100219 /* Query the topology map from the platform */
220 topology_tree = plat_get_power_domain_tree_desc();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100221
Soby Mathew67487842015-07-13 14:10:57 +0100222 /* Populate the power domain arrays using the platform topology map */
Pankaj Guptaab4df502019-10-15 15:44:45 +0530223 psci_plat_core_count = populate_power_domain_tree(topology_tree);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100224
Soby Mathew67487842015-07-13 14:10:57 +0100225 /* Update the CPU limits for each node in psci_non_cpu_pd_nodes */
226 psci_update_pwrlvl_limits();
227
Manish Pandeyef738d12024-06-22 00:00:18 +0100228 /* Initialise the warmboot entrypoints */
229 populate_cpu_data();
230
Soby Mathew67487842015-07-13 14:10:57 +0100231 /* Populate the mpidr field of cpu node for this CPU */
Boyan Karatotev3b802102024-11-06 16:26:15 +0000232 psci_cpu_pd_nodes[cpu_idx].mpidr =
Soby Mathew67487842015-07-13 14:10:57 +0100233 read_mpidr() & MPIDR_AFFINITY_MASK;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100234
Soby Mathew67487842015-07-13 14:10:57 +0100235 psci_init_req_local_pwr_states();
Achin Gupta4f6ad662013-10-25 09:08:21 +0100236
237 /*
Soby Mathew67487842015-07-13 14:10:57 +0100238 * Set the requested and target state of this CPU and all the higher
239 * power domain levels for this CPU to run.
Achin Gupta4f6ad662013-10-25 09:08:21 +0100240 */
Boyan Karatotev3b802102024-11-06 16:26:15 +0000241 psci_set_pwr_domains_to_run(cpu_idx, PLAT_MAX_PWR_LVL);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100242
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100243 (void) plat_setup_psci_ops((uintptr_t)lib_args->mailbox_ep,
244 &psci_plat_pm_ops);
245 assert(psci_plat_pm_ops != NULL);
Achin Gupta4f6ad662013-10-25 09:08:21 +0100246
Soby Mathew7a3d4bd2016-09-09 11:33:58 +0100247 /*
248 * Flush `psci_plat_pm_ops` as it will be accessed by secondary CPUs
Jeenu Viswambharana10d3632017-01-06 14:58:11 +0000249 * during warm boot, possibly before data cache is enabled.
Soby Mathew7a3d4bd2016-09-09 11:33:58 +0100250 */
Jeenu Viswambharana10d3632017-01-06 14:58:11 +0000251 psci_flush_dcache_range((uintptr_t)&psci_plat_pm_ops,
Soby Mathew7a3d4bd2016-09-09 11:33:58 +0100252 sizeof(psci_plat_pm_ops));
253
Soby Mathew90e82582015-01-07 11:10:22 +0000254 /* Initialize the psci capability */
255 psci_caps = PSCI_GENERIC_CAP;
256
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530257 if (psci_plat_pm_ops->pwr_domain_off != NULL) {
Soby Mathew90e82582015-01-07 11:10:22 +0000258 psci_caps |= define_psci_cap(PSCI_CPU_OFF);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530259 }
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100260 if ((psci_plat_pm_ops->pwr_domain_on != NULL) &&
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530261 (psci_plat_pm_ops->pwr_domain_on_finish != NULL)) {
Soby Mathew90e82582015-01-07 11:10:22 +0000262 psci_caps |= define_psci_cap(PSCI_CPU_ON_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530263 }
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100264 if ((psci_plat_pm_ops->pwr_domain_suspend != NULL) &&
265 (psci_plat_pm_ops->pwr_domain_suspend_finish != NULL)) {
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530266 if (psci_plat_pm_ops->validate_power_state != NULL) {
Samuel Hollanda1d5ac62021-04-28 17:52:02 -0500267 psci_caps |= define_psci_cap(PSCI_CPU_SUSPEND_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530268 }
269 if (psci_plat_pm_ops->get_sys_suspend_power_state != NULL) {
Soby Mathewc0aff0e2014-12-17 14:47:57 +0000270 psci_caps |= define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530271 }
Wing Lib88a4412022-09-14 13:18:15 -0700272#if PSCI_OS_INIT_MODE
273 psci_caps |= define_psci_cap(PSCI_SET_SUSPEND_MODE);
274#endif
Soby Mathewc0aff0e2014-12-17 14:47:57 +0000275 }
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530276 if (psci_plat_pm_ops->system_off != NULL) {
Soby Mathew90e82582015-01-07 11:10:22 +0000277 psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530278 }
279 if (psci_plat_pm_ops->system_reset != NULL) {
Soby Mathew90e82582015-01-07 11:10:22 +0000280 psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530281 }
282 if (psci_plat_pm_ops->get_node_hw_state != NULL) {
Jeenu Viswambharan28d3d612016-08-03 15:54:50 +0100283 psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530284 }
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100285 if ((psci_plat_pm_ops->read_mem_protect != NULL) &&
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530286 (psci_plat_pm_ops->write_mem_protect != NULL)) {
Roberto Vargasd4c596b2017-08-03 08:16:16 +0100287 psci_caps |= define_psci_cap(PSCI_MEM_PROTECT);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530288 }
289 if (psci_plat_pm_ops->mem_protect_chk != NULL) {
Roberto Vargasd4c596b2017-08-03 08:16:16 +0100290 psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530291 }
292 if (psci_plat_pm_ops->system_reset2 != NULL) {
Roberto Vargas36a8f8f2017-07-26 09:23:09 +0100293 psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64);
Maheedhar Bollapallic7b0a282024-04-25 11:47:27 +0530294 }
Yatharth Kochar170fb932016-05-09 18:26:35 +0100295#if ENABLE_PSCI_STAT
296 psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
297 psci_caps |= define_psci_cap(PSCI_STAT_COUNT_AARCH64);
298#endif
299
Achin Gupta7421b462014-02-01 18:53:26 +0000300 return 0;
Achin Gupta4f6ad662013-10-25 09:08:21 +0100301}
Soby Mathewcf0b1492016-04-29 19:01:30 +0100302
303/*******************************************************************************
304 * This duplicates what the primary cpu did after a cold boot in BL1. The same
305 * needs to be done when a cpu is hotplugged in. This function could also over-
306 * ride any EL3 setup done by BL1 as this code resides in rw memory.
307 ******************************************************************************/
308void psci_arch_setup(void)
309{
Antonio Nino Diaz6b7b0f32018-07-17 15:10:08 +0100310#if (ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_GENERIC_TIMER)
Soby Mathewcf0b1492016-04-29 19:01:30 +0100311 /* Program the counter frequency */
312 write_cntfrq_el0(plat_get_syscnt_freq2());
Etienne Carriere86e26832017-11-08 14:41:47 +0100313#endif
Soby Mathewcf0b1492016-04-29 19:01:30 +0100314
315 /* Initialize the cpu_ops pointer. */
316 init_cpu_ops();
Jeenu Viswambharan10bcd762017-01-03 11:01:51 +0000317
318 /* Having initialized cpu_ops, we can now print errata status */
319 print_errata_status();
Alexei Fedoroved108b52019-09-13 14:11:59 +0100320
Soby Mathewcf0b1492016-04-29 19:01:30 +0100321}
Soby Mathew727e5232016-05-05 14:11:23 +0100322
323/******************************************************************************
324 * PSCI Library interface to initialize the cpu context for the next non
325 * secure image during cold boot. The relevant registers in the cpu context
326 * need to be retrieved and programmed on return from this interface.
327 *****************************************************************************/
328void psci_prepare_next_non_secure_ctx(entry_point_info_t *next_image_info)
329{
330 assert(GET_SECURITY_STATE(next_image_info->h.attr) == NON_SECURE);
331 cm_init_my_context(next_image_info);
332 cm_prepare_el3_exit(NON_SECURE);
333}