blob: f1c4b11f47a0acaa8a6ec31faa24d378141c3433 [file] [log] [blame]
Olivier Deprezf17eadc2021-01-25 15:33:38 +01001/*
2 * Copyright 2021 The Hafnium Authors.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
7 */
8
Olivier Deprez148b5602022-03-16 17:13:06 +01009#include "hf/arch/plat/psci.h"
10
11#include "hf/api.h"
12#include "hf/check.h"
Olivier Deprezf17eadc2021-01-25 15:33:38 +010013#include "hf/cpu.h"
Karl Meakin902af082024-11-28 14:58:38 +000014#include "hf/ffa/notifications.h"
Olivier Deprez70f8a4a2022-09-26 09:17:56 +020015#include "hf/vm.h"
Olivier Deprezf17eadc2021-01-25 15:33:38 +010016
17#include "psci.h"
18
Max Shvetsov9c0ebe42020-08-27 12:37:57 +010019void cpu_entry(struct cpu *c);
20
Olivier Deprezf17eadc2021-01-25 15:33:38 +010021/**
22 * Returns zero in context of the SPMC as it does not rely
23 * on the EL3 PSCI framework.
24 */
25uint32_t plat_psci_version_get(void)
26{
27 return 0;
28}
29
30/**
31 * Initialize the platform power managment module in context of
32 * running the SPMC.
33 */
34void plat_psci_init(void)
35{
Max Shvetsov9c0ebe42020-08-27 12:37:57 +010036 struct ffa_value res;
37
Olivier Deprezd614d322021-06-18 15:21:00 +020038 /*
39 * DEN0077A FF-A v1.1 Beta0 section 18.3.2.1.1
40 * Register the SPMC secondary cold boot entry point at the secure
41 * physical FF-A instance (to the SPMD).
42 */
Olivier Depreze8015b422025-08-28 09:53:42 +020043 res = smc_ffa_call_ext(
Max Shvetsov9c0ebe42020-08-27 12:37:57 +010044 (struct ffa_value){.func = FFA_SECONDARY_EP_REGISTER_64,
45 .arg1 = (uintreg_t)&cpu_entry});
46
Olivier Deprezad5f3c12025-04-10 11:27:14 +020047 if (res.func != FFA_SUCCESS_32 && res.func != FFA_SUCCESS_64) {
Max Shvetsov9c0ebe42020-08-27 12:37:57 +010048 panic("FFA_SECONDARY_EP_REGISTER_64 failed");
49 }
Olivier Deprezf17eadc2021-01-25 15:33:38 +010050}
51
52void plat_psci_cpu_suspend(uint32_t power_state)
53{
54 (void)power_state;
55}
56
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -060057/** Switch to the normal world vCPU pinned on this physical CPU now. */
58static struct vcpu *plat_psci_switch_to_other_world(struct cpu *c)
59{
60 struct vcpu_locked other_world_vcpu_locked;
61 struct vm *other_world_vm = vm_find(HF_OTHER_WORLD_ID);
62 struct vcpu *other_world_vcpu;
63
64 CHECK(other_world_vm != NULL);
65
66 other_world_vcpu = vm_get_vcpu(other_world_vm, cpu_index(c));
67
68 CHECK(other_world_vcpu != NULL);
69
70 other_world_vcpu_locked = vcpu_lock(other_world_vcpu);
71
72 /*
73 * Return FFA_MSG_WAIT_32 to indicate to SPMD that SPMC
74 * has successfully finished initialization on this
75 * CPU.
76 */
77 arch_regs_set_retval(&other_world_vcpu->regs,
78 (struct ffa_value){.func = FFA_MSG_WAIT_32});
79
80 other_world_vcpu->state = VCPU_STATE_WAITING;
81 vcpu_unlock(&other_world_vcpu_locked);
82
83 return other_world_vcpu;
84}
85
86/**
87 * Check if there is at least one SP whose execution context needs to be
88 * bootstrapped on this physical CPU.
89 */
90static struct vm *plat_psci_get_boot_vm(struct cpu *c)
91{
92 struct vm *boot_vm;
93
94 if (cpu_index(c) == PRIMARY_CPU_IDX) {
95 boot_vm = vm_get_boot_vm();
96
97 /*
98 * On the primary CPU, at least one SP will exist whose
99 * execution context shall be bootstrapped.
100 */
101 CHECK(boot_vm != NULL);
102 } else {
103 boot_vm = vm_get_boot_vm_secondary_core();
104
105 /*
106 * It is possible that no SP might exist that needs its
107 * execution context to be bootstrapped on secondary CPU. This
108 * can happen if all the SPs in the system are UP partitions and
109 * hence, have no vCPUs pinned to secondary CPUs.
110 */
111 if (boot_vm != NULL) {
112 assert(boot_vm->vcpu_count > 1);
113 }
114 }
115
116 return boot_vm;
117}
118
Olivier Deprez148b5602022-03-16 17:13:06 +0100119struct vcpu *plat_psci_cpu_resume(struct cpu *c)
Olivier Deprezf17eadc2021-01-25 15:33:38 +0100120{
Olivier Deprez148b5602022-03-16 17:13:06 +0100121 struct vcpu_locked vcpu_locked;
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600122 struct vm *boot_vm;
123 struct vcpu *boot_vcpu;
Olivier Deprez70f8a4a2022-09-26 09:17:56 +0200124
Olivier Deprez148b5602022-03-16 17:13:06 +0100125 cpu_on(c);
126
127 arch_cpu_init(c);
128
129 /* Initialize SRI for running core. */
Karl Meakin117c8082024-12-04 16:03:28 +0000130 ffa_notifications_sri_init(c);
Olivier Deprez148b5602022-03-16 17:13:06 +0100131
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600132 boot_vm = plat_psci_get_boot_vm(c);
Madhukar Pappireddya49ba162024-11-25 09:40:45 -0600133
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600134 if (boot_vm == NULL) {
135 return plat_psci_switch_to_other_world(c);
Max Shvetsov9c0ebe42020-08-27 12:37:57 +0100136 }
Olivier Deprez148b5602022-03-16 17:13:06 +0100137
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600138 /* Obtain the vCPU for the boot SP on this CPU. */
139 boot_vcpu = vm_get_vcpu(boot_vm, cpu_index(c));
Olivier Deprez148b5602022-03-16 17:13:06 +0100140
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600141 /* Lock the vCPU to update its fields. */
142 vcpu_locked = vcpu_lock(boot_vcpu);
143
144 /* Pin the vCPU to this CPU. */
145 boot_vcpu->cpu = c;
146
147 vcpu_secondary_reset_and_start(vcpu_locked, boot_vcpu->vm->secondary_ep,
Olivier Deprez148b5602022-03-16 17:13:06 +0100148 0ULL);
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600149
Madhukar Pappireddyd6c055d2025-05-08 15:35:46 -0500150 /* Set the vCPU's state to STARTING. */
151 boot_vcpu->state = VCPU_STATE_STARTING;
152 boot_vcpu->regs_available = false;
Olivier Deprez148b5602022-03-16 17:13:06 +0100153
154 /* vCPU restarts in runtime model for SP initialization. */
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600155 boot_vcpu->rt_model = RTM_SP_INIT;
Olivier Deprez148b5602022-03-16 17:13:06 +0100156
157 /* Set the designated GP register with the core linear id. */
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600158 vcpu_set_phys_core_idx(boot_vcpu);
Olivier Deprez148b5602022-03-16 17:13:06 +0100159
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600160 if (cpu_index(c) == PRIMARY_CPU_IDX) {
161 /*
162 * Boot information is passed by the SPMC to the SP's execution
163 * context only on the primary CPU.
164 */
165 vcpu_set_boot_info_gp_reg(boot_vcpu);
166 }
Olivier Deprez148b5602022-03-16 17:13:06 +0100167
Olivier Deprez148b5602022-03-16 17:13:06 +0100168 vcpu_unlock(&vcpu_locked);
169
Madhukar Pappireddy44b85ff2024-11-25 10:29:22 -0600170 return boot_vcpu;
Olivier Deprezf17eadc2021-01-25 15:33:38 +0100171}